import Foundation
import Photos
import CoreLocation
import UIKit
import Combine

// MARK: - 全局地址信息类型
struct GlobalLocationAddressInfo {
    let country: String?
    let province: String?
    let city: String?
    let district: String?
    let township: String?
    let street: String?
    let poiName: String?
    let formattedAddress: String?
    
    var displayName: String {
        // 🎯 优先显示POI名称（具体地点），如果没有则显示格式化地址
        if let poiName = poiName, !poiName.isEmpty {
            return poiName
        }
        return formattedAddress ?? street ?? city ?? "未知地址"
    }
    
    // 🎯 新增：获取详细地址（包含POI和街道信息）
    var detailedAddress: String {
        var parts: [String] = []
        
        if let poiName = poiName, !poiName.isEmpty {
            parts.append(poiName)
        }
        
        if let street = street, !street.isEmpty {
            parts.append(street)
        }
        
        if let district = district, !district.isEmpty {
            parts.append(district)
        }
        
        if let city = city, !city.isEmpty {
            parts.append(city)
        }
        
        return parts.isEmpty ? "未知地址" : parts.joined(separator: ", ")
    }
    
    // 🎯 新增：获取简洁地址（仅POI名称）
    var simpleAddress: String {
        return poiName ?? street ?? city ?? "未知地址"
    }
}

// MARK: - 地理编码服务类型枚举
enum GeocodingServiceType: String, CaseIterable {
    case apple = "apple"
    case google = "google"
    case amap = "amap"
    case openStreetMap = "openStreetMap"
    
    var displayName: String {
        switch self {
        case .apple:
            return "Apple CoreLocation"
        case .google:
            return "Google Maps API"
        case .amap:
            return "高德地图API"
        case .openStreetMap:
            return "OpenstreetMap Nominatim"
        }
    }
}

@MainActor
class PhotoService: ObservableObject {
    @Published var photos: [PhotoData] = []
    @Published var authorizationStatus: PHAuthorizationStatus = .notDetermined
    @Published var isLoading = false
    @Published var errorMessage: String?
    @Published var isGeocodingInProgress = false
    @Published var geocodingProgress: Double = 0.0
    @Published var geocodingCurrentPhoto = 0
    @Published var geocodingTotalPhotos = 0
    @Published var totalPhotoCount = 0  // 本机总照片数
    @Published var unknownPhotosCount = 0  // 🚀 新增：未知照片数量，用于UI实时更新
    
    private let geocoder = CLGeocoder()
    private var locationCache: [CLLocationCoordinate2D: LocationInfo] = [:]
    private var processedPhotoIds: Set<String> = []
    private let processedPhotosKey = "ProcessedPhotoIds"
    private let photoDataCacheKey = "PhotoDataCache"
    private let cacheFileName = "PhotoDataCache.json"
    
    // MARK: - 新的持久化数据管理
    private var photoDataMap: [String: SerializablePhotoData] = [:] // 照片ID -> 持久化数据
    private let photoDataMapKey = "PhotoDataMap"
    
    // MARK: - 测试模式配置
    private let testMode = false  // 测试模式：关闭测试模式，加载所有照片
    private let testPhotoCount = 50000  // 测试照片数量（支持更多照片）
    
    // MARK: - 性能优化配置
    private let optimizedBatchSize = 200  // 增加批处理大小（适应17000张照片）
    private let uiUpdateInterval = 500   // 每500张照片更新一次UI（减少UI更新频率）
    private let memoryCleanupInterval = 100 // 每100张照片清理一次内存（减少清理频率）
    private let geocodingBatchSize = 50  // 增加地理编码批处理大小（提高并发效率）
    private let geocodingDelay: TimeInterval = 0.1 // 进一步减少延迟
    
    // MARK: - 地址信息本地缓存
    private let addressCacheKey = "AddressCache"
    private var addressCache: [String: SerializableLocationInfo] = [:]
    
    // 🚀 新增：地理编码API调用优化
    private let geocodingSemaphore = DispatchSemaphore(value: 10) // 增加并发API调用数量（适应17000张照片）
    private let geocodingQueue = DispatchQueue(label: "com.phototour.geocoding", qos: .userInitiated, attributes: .concurrent)
    private var geocodingTaskGroup: TaskGroup<Void>?
    
    // 🚀 新增：地址缓存统计
    private var cacheHitCount = 0
    private var cacheMissCount = 0
    private var apiCallCount = 0

    // 🚀 新增：相邻照片时间维度优化
    private let timeSimilarityThreshold: TimeInterval = 30.0 // 30秒内相似
    private var timeBasedCacheHitCount = 0
    private var timeBasedCacheMissCount = 0
    private var lastProcessedPhoto: PhotoData? // 记录上一张处理的照片
    
    // 🚀 新增：防止重复注册监听器的标志
    private static var isObserverRegistered = false

    private func coordinateKey(_ coordinate: CLLocationCoordinate2D) -> String {
        // 保留6位小数，避免浮点误差导致缓存命中失败
        String(format: "%.6f,%.6f", coordinate.latitude, coordinate.longitude)
    }
    


    private func loadAddressCache() {
        if let data = UserDefaults.standard.data(forKey: addressCacheKey),
           let dict = try? JSONDecoder().decode([String: SerializableLocationInfo].self, from: data) {
            addressCache = dict
            print("[PhotoService.loadAddressCache] 📂 地址缓存加载成功: \(addressCache.count) 条记录")
            
            // 🚀 新增：缓存统计信息
            let totalCoordinates = dict.count
            let completeAddresses = dict.values.filter { 
                $0.address != nil && $0.city != nil && $0.country != nil 
            }.count
            print("[PhotoService.loadAddressCache] 📂 缓存统计: 总坐标 \(totalCoordinates) 个，完整地址 \(completeAddresses) 个")
        } else {
            print("[PhotoService.loadAddressCache] 📂 地址缓存为空，将创建新缓存")
        }
    }

    private func saveAddressCache() {
        if let data = try? JSONEncoder().encode(addressCache) {
            UserDefaults.standard.set(data, forKey: addressCacheKey)
            print("[PhotoService.saveAddressCache] 💾 地址缓存已保存: \(addressCache.count) 条记录")
            
            // 🚀 新增：保存缓存统计
            let stats = [
                "cacheHitCount": cacheHitCount,
                "cacheMissCount": cacheMissCount,
                "apiCallCount": apiCallCount,
                "totalCacheSize": addressCache.count
            ]
            UserDefaults.standard.set(stats, forKey: "AddressCacheStats")
        } else {
            print("[PhotoService.saveAddressCache] ❌ 地址缓存保存失败")
        }
    }
    
    // 🚀 新增：获取缓存统计信息
    private func getCacheStats() -> (hits: Int, misses: Int, apiCalls: Int, totalCache: Int) {
        let stats = UserDefaults.standard.dictionary(forKey: "AddressCacheStats") ?? [:]
        let hits = stats["cacheHitCount"] as? Int ?? 0
        let misses = stats["cacheMissCount"] as? Int ?? 0
        let apiCalls = stats["apiCallCount"] as? Int ?? 0
        let totalCache = stats["totalCacheSize"] as? Int ?? 0
        return (hits, misses, apiCalls, totalCache)
    }
    
    // MARK: - 新的持久化数据管理方法
    
    private func loadPhotoDataMap() {
        if let data = UserDefaults.standard.data(forKey: photoDataMapKey),
           let map = try? JSONDecoder().decode([String: SerializablePhotoData].self, from: data) {
            photoDataMap = map
            print("[PhotoService.loadPhotoDataMap] 📂 照片数据映射加载成功: \(photoDataMap.count) 条记录")
        } else {
            print("[PhotoService.loadPhotoDataMap] 📂 照片数据映射为空，将创建新映射")
        }
    }
    
    private func savePhotoDataMap() {
        if let data = try? JSONEncoder().encode(photoDataMap) {
            UserDefaults.standard.set(data, forKey: photoDataMapKey)
            // 🚀 优化：减少日志输出频率，避免重复日志
            // print("[PhotoService.savePhotoDataMap] 💾 照片数据映射已保存: \(photoDataMap.count) 条记录")
        } else {
            print("[PhotoService.savePhotoDataMap] ❌ 照片数据映射保存失败")
        }
    }
    
    private func getPhotoDataFromMap(_ photoId: String) -> SerializablePhotoData? {
        return photoDataMap[photoId]
    }
    
    private func updatePhotoDataInMap(_ photoId: String, _ photoData: PhotoData) {
        let serializableData = SerializablePhotoData(from: photoData)
        photoDataMap[photoId] = serializableData
        // 🚀 优化：减少日志输出频率，避免重复日志
        // print("📝 更新照片数据映射: \(photoId)")
    }
    
    // MARK: - 初始化
    
    init() {
        let startTime = Date()
        print("[PhotoService.init] 📸 PhotoService 初始化开始 - \(startTime)")
        
        // 检查是否需要清除持久化数据（只在第一次运行或测试时）
        let shouldClearData = UserDefaults.standard.bool(forKey: "FirstRun")
        if shouldClearData {
            // 强制清除所有缓存，确保重新分析照片
            clearAllCache()
            print("[PhotoService.init] 🗑️ 已清除所有缓存数据 - \(Date())")
            
            // 强制清除持久化数据，重新加载500张照片
            UserDefaults.standard.removeObject(forKey: photoDataMapKey)
            print("[PhotoService.init] 🗑️ 已清除持久化数据，将重新加载500张照片 - \(Date())")
            
            // 标记已不是第一次运行
            UserDefaults.standard.set(false, forKey: "FirstRun")
        } else {
            print("[PhotoService.init] 📂 使用现有持久化数据 - \(Date())")
        }
        
        loadAddressCache()
        loadPhotoDataMap() // 加载新的持久化数据映射
        loadKnownAddresses() // 加载已知解析地址
        
        // 🚀 新增：检查并修复地理编码配置
        checkAndFixGeocodingConfig()
        
        // 🚀 优化：在后台进行缓存预热
        Task {
            await warmupAddressCache()
        }
        
        // 🚀 新增：监听地点分析通知
        setupLocationAnalysisNotification()
        
        let endTime = Date()
        let duration = endTime.timeIntervalSince(startTime)
        print("[PhotoService.init] 📸 PhotoService 初始化完成 - \(endTime) (耗时: \(String(format: "%.2f", duration))秒)")
    }
    
    // MARK: - 权限管理
    
    func requestAuthorization() async {
        let status = await PHPhotoLibrary.requestAuthorization(for: .readWrite)
        await MainActor.run {
            self.authorizationStatus = status
            // 🚀 修复：移除这里的loadAllPhotos调用，避免重复调用
            // 让ContentView统一处理照片加载
        }
    }
    
    private func checkAuthorizationStatus() {
        authorizationStatus = PHPhotoLibrary.authorizationStatus(for: .readWrite)
    }
    
    // MARK: - 获取本机总照片数
    func getTotalPhotoCount() async {
        guard authorizationStatus == .authorized || authorizationStatus == .limited else {
            await MainActor.run {
                self.totalPhotoCount = 0
            }
            return
        }
        
        let fetchOptions = PHFetchOptions()
        fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
        
        let fetchResult = PHAsset.fetchAssets(with: .image, options: fetchOptions)
        let totalCount = fetchResult.count
        
        await MainActor.run {
            self.totalPhotoCount = totalCount
            print("[PhotoService.getTotalPhotoCount] 📸 本机总照片数: \(totalCount) 张")
        }
    }
    
    // MARK: - 测试控制方法
    
    func setFirstRun() {
        UserDefaults.standard.set(true, forKey: "FirstRun")
        print("[PhotoService.setFirstRun] 🔄 已设置为第一次运行模式，下次启动将清除所有数据")
    }
    
    func clearFirstRunFlag() {
        UserDefaults.standard.set(false, forKey: "FirstRun")
        print("[PhotoService.clearFirstRunFlag] ✅ 已清除第一次运行标志，下次启动将使用持久化数据")
    }
    
    // MARK: - 本地缓存管理
    
    private func getCacheDirectory() -> URL {
        let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
        return paths[0]
    }
    
    private func savePhotoDataCache() {
        let serializablePhotos = photos.map { SerializablePhotoData(from: $0) }
        
        do {
            let encoder = JSONEncoder()
            encoder.dateEncodingStrategy = .iso8601
            let data = try encoder.encode(serializablePhotos)
            try data.write(to: getCacheFilePath())
            print("[PhotoService.savePhotoDataCache] 💾 照片缓存已保存: \(serializablePhotos.count) 张照片")
        } catch {
            print("[PhotoService.savePhotoDataCache] ❌ 照片缓存保存失败: \(error.localizedDescription)")
        }
    }
    
    // 🚫 废弃：此方法已被新的持久化数据映射替代
    private func loadPhotoDataCache() async -> Bool {
        return false // 直接返回false，强制使用新的持久化数据映射
    }
    
    private func loadPhotosFromLibrary() async {
        print("[PhotoService.loadPhotosFromLibrary] 📸 从相册加载照片...")
        
        let fetchResult = PHAsset.fetchAssets(with: .image, options: nil)
        let totalCount = fetchResult.count
        print("[PhotoService.loadPhotosFromLibrary] 📸 相册照片总数: \(totalCount) 张")
        
        if totalCount == 0 {
            await MainActor.run {
                isLoading = false
                errorMessage = "相册中没有照片"
            }
            return
        }
        
        // 🚀 修复：始终加载所有照片，不限制数量
        let actualCount = totalCount
        print("[PhotoService.loadPhotosFromLibrary] 📸 处理模式: 加载所有 \(actualCount) 张照片")
        
        var processedCount = 0
        var newPhotos: [PhotoData] = []
        
        // 分批处理照片
        for i in stride(from: 0, to: actualCount, by: optimizedBatchSize) {
            let endIndex = min(i + optimizedBatchSize, actualCount)
            let batchAssets = fetchResult.objects(at: IndexSet(integersIn: i..<endIndex))
            
            print("[PhotoService.loadPhotosFromLibrary] 📸 处理批次 \(i/optimizedBatchSize + 1)/\(Int(ceil(Double(actualCount)/Double(optimizedBatchSize))))")
            
            for asset in batchAssets {
                let photoId = asset.localIdentifier
                
                if processedPhotoIds.contains(photoId) {
                    continue
                }
                
                if let existingData = getPhotoDataFromMap(photoId) {
                    let photoData = existingData.toPhotoData(asset: asset)
                    newPhotos.append(photoData)
                    processedPhotoIds.insert(photoId)
                    processedCount += 1
                } else {
                    if let photoData = await extractPhotoData(from: asset) {
                        newPhotos.append(photoData)
                        processedPhotoIds.insert(photoId)
                        processedCount += 1
                        updatePhotoDataInMap(photoId, photoData)
                    }
                }
                
                if processedCount % memoryCleanupInterval == 0 {
                    await cleanupMemory()
                }
            }
            
            await cleanupMemory()
            try? await Task.sleep(nanoseconds: 200_000_000)
        }
        
        let photosWithLocation = newPhotos.filter { $0.location != nil }
        let photosWithoutLocation = newPhotos.filter { $0.location == nil }
        
        print("[PhotoService.loadPhotosFromLibrary] 📸 照片加载完成: 总照片数 \(newPhotos.count), 有地理信息 \(photosWithLocation.count), 无地理信息 \(photosWithoutLocation.count)")
        
        if newPhotos.isEmpty {
            await MainActor.run {
                isLoading = false
                errorMessage = "没有成功加载任何照片"
            }
            return
        }
        
        await MainActor.run {
            self.photos = newPhotos
            isLoading = false
        }
        
        // 🚀 修改：暂停自动地理编码，用户需手动触发
        print("📍 照片加载完成，共 \(newPhotos.count) 张照片")
        print("📍 已暂停自动地理编码，请在测试界面手动触发解析")
        
        // 统计需要地理编码的照片数量
        let photosNeedingGeocoding = newPhotos.filter { photo in
            guard let location = photo.location else { return false }
            let hasAddress = location.address != nil && location.address != "未知"
            let hasCity = location.city != nil && location.city != "未知"
            let hasCountry = location.country != nil && location.country != "未知"
            return !hasAddress || !hasCity || !hasCountry
        }
        
        print("📍 统计：\(photosNeedingGeocoding.count) 张照片需要地理编码")
        
        savePhotoDataMap()
    }
    
    private func savePhotoDataToCache(_ photos: [PhotoData]) async {
        print("[PhotoService.savePhotoDataToCache] 🔍 === 功能B：照片的分析结果写入持久化文件 ===")
        
        let serializablePhotos = photos.map { SerializablePhotoData(from: $0) }
        
        // 检查第一张照片的数据完整性
        if let firstPhoto = serializablePhotos.first {
            print("[PhotoService.savePhotoDataToCache] 🔍 === 第一张照片数据检查 ===")
            print("[PhotoService.savePhotoDataToCache] 🔍 照片ID: \(firstPhoto.id)")
            print("[PhotoService.savePhotoDataToCache] 🔍 拍摄时间: \(firstPhoto.creationDate.description)")
            print("[PhotoService.savePhotoDataToCache] 🔍 是否有地理坐标: \(firstPhoto.location != nil)")
            if let location = firstPhoto.location {
                print("[PhotoService.savePhotoDataToCache] 🔍 坐标: \(location.latitude), \(location.longitude)")
                print("[PhotoService.savePhotoDataToCache] 🔍 地址: \(location.address ?? "未知")")
                print("[PhotoService.savePhotoDataToCache] 🔍 城市: \(location.city ?? "未知")")
            }
            print("[PhotoService.savePhotoDataToCache] 🔍 === 第一张照片数据检查完成 ===")
        }
        
        do {
            let encoder = JSONEncoder()
            encoder.dateEncodingStrategy = .iso8601
            let data = try encoder.encode(serializablePhotos)
            try data.write(to: getCacheFilePath())
            print("[PhotoService.savePhotoDataToCache] 💾 照片缓存已保存: \(serializablePhotos.count) 张照片")
            print("[PhotoService.savePhotoDataToCache] 💾 缓存文件大小: \(data.count) 字节")
            print("[PhotoService.savePhotoDataToCache] ✅ 功能B成功：照片的分析结果已写入持久化文件")
        } catch {
            print("[PhotoService.savePhotoDataToCache] ❌ 照片缓存保存失败: \(error.localizedDescription)")
            print("[PhotoService.savePhotoDataToCache] ❌ 功能B失败：持久化文件写入失败")
        }
    }
    
    private func performGeocoding(for photos: [PhotoData]) async {
        print("[PhotoService.performGeocoding] 📍 === 地理编码开始 ===")
        
        guard !isGeocodingInProgress else { return }
        
        await MainActor.run {
            self.isGeocodingInProgress = true
            self.geocodingTotalPhotos = photos.count
            self.geocodingCurrentPhoto = 0
            self.geocodingProgress = 0.0
        }
        
        // 只对有坐标但缺少详细地址的照片进行地理编码
        var coordinatesToGeocode: [(CLLocationCoordinate2D, Int)] = []
        for (index, photo) in photos.enumerated() {
            if let loc = photo.location {
                let coordinate = loc.coordinate
                // 只要没有详细地址就加入地理编码队列
                if loc.address == nil || loc.city == nil || loc.country == nil {
                    coordinatesToGeocode.append((coordinate, index))
                }
            }
        }
        print("[PhotoService.performGeocoding] 📍 需要地理编码的坐标数量: \(coordinatesToGeocode.count)")
        var successCount = 0
        var failCount = 0
        
        // 🚀 性能优化：批量地理编码，减少API调用频率
        let batchSize = geocodingBatchSize
        let totalBatches = Int(ceil(Double(coordinatesToGeocode.count)/Double(batchSize)))
        
        print("[PhotoService.performGeocoding] 📍 开始批量地理编码: \(coordinatesToGeocode.count) 个坐标，\(totalBatches) 个批次")
        
        for i in stride(from: 0, to: coordinatesToGeocode.count, by: batchSize) {
            let endIndex = min(i + batchSize, coordinatesToGeocode.count)
            let batch = Array(coordinatesToGeocode[i..<endIndex])
            let currentBatch = i/batchSize + 1
            
            print("[PhotoService.performGeocoding] 📍 地理编码批次: \(currentBatch)/\(totalBatches) - 处理 \(batch.count) 个坐标")
            
            // 🚀 优化：使用TaskGroup进行并发处理
            let results = await withTaskGroup(of: (CLLocationCoordinate2D, Int, LocationInfo?).self) { group in
                for (coordinate, photoIndex) in batch {
                    group.addTask {
                        if let locationInfo = await self.geocodeCoordinate(coordinate) {
                            return (coordinate, photoIndex, locationInfo)
                        } else {
                            return (coordinate, photoIndex, nil)
                        }
                    }
                }
                
                var results: [(CLLocationCoordinate2D, Int, LocationInfo?)] = []
                for await result in group {
                    results.append(result)
                }
                return results
            }
            
            // 处理批次结果
            for (coordinate, photoIndex, locationInfo) in results {
                if let locationInfo = locationInfo {
                successCount += 1
                locationCache[coordinate] = locationInfo
                    
                    // 批量更新UI，减少MainActor调用
                await MainActor.run {
                    if photoIndex < self.photos.count {
                        self.photos[photoIndex].location = locationInfo
                            // 延迟更新持久化数据，避免频繁写入
                        self.updatePhotoDataInMap(self.photos[photoIndex].id, self.photos[photoIndex])
                    }
                }
            } else {
                failCount += 1
                print("📍 照片#\(photoIndex + 1) 地理编码失败，坐标: \(coordinate.latitude), \(coordinate.longitude)")
            }
                
            await MainActor.run {
                self.geocodingCurrentPhoto += 1
                // 🚀 优化：减少进度更新频率，避免UI阻塞
                if self.geocodingCurrentPhoto % 10 == 0 || self.geocodingCurrentPhoto == self.geocodingTotalPhotos {
                    self.geocodingProgress = Double(self.geocodingCurrentPhoto) / Double(self.geocodingTotalPhotos)
                }
            }
            }
            
            // 🚀 优化：减少暂停时间，增加批处理效率
            if (i + batchSize) < coordinatesToGeocode.count {
                print("⏸️ 地理编码批次暂停...")
                try? await Task.sleep(nanoseconds: UInt64(geocodingDelay * 1_000_000_000))
            }
            
            // 每3个批次保存一次持久化数据
            if (i / batchSize + 1) % 3 == 0 {
                await MainActor.run {
                    self.savePhotoDataMap()
                }
            }
        }
        await MainActor.run {
            self.isGeocodingInProgress = false
            let successRate = coordinatesToGeocode.count > 0 ? Double(successCount) / Double(coordinatesToGeocode.count) * 100 : 0
            print("📍 地理编码完成，共处理 \(coordinatesToGeocode.count) 个坐标 - \(Date())")
            print("📍 成功: \(successCount) 个，失败: \(failCount) 个，成功率: \(String(format: "%.1f", successRate))%")
        }
    }
    
    // MARK: - 补充地理编码方法
    
    private func performGeocodingForIncompletePhotos(_ photos: [PhotoData]) async {
        let startTime = Date()
        print("📍 开始为不完整地址的照片进行地理编码... - \(startTime)")
        print("📍 需要处理 \(photos.count) 张照片的地理信息")
        
        // 🚀 新增：按时间排序照片，提高时间维度优化命中率
        let sortedPhotos = photos.sorted { $0.creationDate < $1.creationDate }
        print("📍 已按时间排序 \(sortedPhotos.count) 张照片，时间范围: \(sortedPhotos.first?.creationDate ?? Date()) 到 \(sortedPhotos.last?.creationDate ?? Date())")
        
        // 更新UI状态
        await MainActor.run {
            self.isGeocodingInProgress = true
            self.geocodingCurrentPhoto = 0
            self.geocodingTotalPhotos = sortedPhotos.count
            self.geocodingProgress = 0.0
        }
        
        var successCount = 0
        var failCount = 0
        
        for (index, photo) in sortedPhotos.enumerated() {
            guard let location = photo.location else { continue }
            
            // 🚀 优化：减少日志输出频率，避免性能影响
            if (index + 1) % 10 == 0 || index == 0 || index == sortedPhotos.count - 1 {
                print("📍 地理编码进度: \(index + 1)/\(sortedPhotos.count) - 照片ID: \(photo.id)")
                print("📍 坐标: \(location.coordinate.latitude), \(location.coordinate.longitude)")
                print("📍 拍摄时间: \(photo.creationDate)")
            }
            
            // 🚀 修改：使用时间维度优化的地理编码函数
            await geocodePhotoLocation(photo)
            
            // 检查地理编码是否成功
            if let updatedPhoto = self.photos.first(where: { $0.id == photo.id }),
               let updatedLocation = updatedPhoto.location,
               updatedLocation.address != nil && updatedLocation.address != "未知" {
                successCount += 1
                
                        // 🚀 优化：减少成功日志输出频率
                if (index + 1) % 20 == 0 || index == 0 || index == sortedPhotos.count - 1 {
                    print("📍 照片 \(photo.id) 地理编码成功: \(updatedLocation.displayName)")
                        }
                        
                        // 立即更新持久化数据
                await MainActor.run {
                    self.updatePhotoDataInMap(photo.id, updatedPhoto)
                    // 🚀 优化：减少频繁保存，改为批量保存
                    // self.savePhotoDataMap()
                }
            } else {
                failCount += 1
                // 🚀 优化：减少失败日志输出频率
                if failCount <= 3 || failCount % 10 == 0 {
                    print("📍 照片 \(photo.id) 地理编码失败")
                }
            }
            
            // 更新进度
            await MainActor.run {
                self.geocodingCurrentPhoto = index + 1
                // 🚀 优化：减少进度更新频率，避免UI阻塞
                if (index + 1) % 10 == 0 || index == photos.count - 1 {
                    self.geocodingProgress = Double(index + 1) / Double(photos.count)
                }
            }
            
            // 每处理5个坐标暂停一次，避免API限制
            if (index + 1) % 5 == 0 {
                print("⏸️ 地理编码暂停，避免API限制...")
                try? await Task.sleep(nanoseconds: 2_000_000_000) // 2秒
            }
            
            // 如果连续失败3次，增加更长的暂停时间
            if failCount > 0 && failCount % 3 == 0 {
                print("⚠️ 连续失败3次，暂停更长时间...")
                try? await Task.sleep(nanoseconds: 5_000_000_000) // 5秒
            }
        }
        
        let endTime = Date()
        let duration = endTime.timeIntervalSince(startTime)
        let successRate = photos.count > 0 ? Double(successCount) / Double(photos.count) * 100 : 0
        print("📍 补充地理编码完成，共处理 \(photos.count) 张照片 - \(endTime) (耗时: \(String(format: "%.2f", duration))秒)")
        print("📍 成功: \(successCount) 张，失败: \(failCount) 张，成功率: \(String(format: "%.1f", successRate))%")
        
        // 完成地理编码
        await MainActor.run {
            self.isGeocodingInProgress = false
            self.geocodingProgress = 1.0
        }
    }
    
    private func cleanupMemory() async {
        // 🚀 性能优化：智能内存管理
        let memoryUsage = getMemoryUsage()
        
        // 只在内存使用较高时才清理
        if memoryUsage > 100 {
            print("💾 内存清理开始，当前使用: \(memoryUsage) MB")
            
            // 清理图片缓存
            ImageCache.shared.clearCache()
            
        // 强制垃圾回收
        autoreleasepool {
            // 清理临时变量
        }
        
            // 如果内存使用过高，强制清理缓存
            if memoryUsage > 120 {
                print("⚠️ 内存使用过高，强制清理缓存...")
            locationCache.removeAll(keepingCapacity: false)
                addressCache.removeAll(keepingCapacity: false)
            
            // 强制垃圾回收
            autoreleasepool {
                // 再次清理
                }
            }
            
            print("💾 内存清理完成，当前使用: \(getMemoryUsage()) MB")
        }
    }
    
    private func getMemoryUsage() -> Int {
        var info = mach_task_basic_info()
        var count = mach_msg_type_number_t(MemoryLayout<mach_task_basic_info>.size)/4
        
        let kerr: kern_return_t = withUnsafeMutablePointer(to: &info) {
            $0.withMemoryRebound(to: integer_t.self, capacity: 1) {
                task_info(mach_task_self_,
                         task_flavor_t(MACH_TASK_BASIC_INFO),
                         $0,
                         &count)
            }
        }
        
        if kerr == KERN_SUCCESS {
            return Int(info.resident_size / 1024 / 1024) // 转换为MB
        }
        return 0
    }
    
    // MARK: - 照片数据提取
    
    private func extractPhotoData(from asset: PHAsset) async -> PhotoData? {
        let photoId = asset.localIdentifier
        let creationDate = asset.creationDate ?? Date()
        
        // 🚀 优化：只读取元数据，不加载图片
        // 不加载缩略图和原图，只保留asset引用，需要时再加载
        let thumbnail: UIImage? = nil  // 不预加载缩略图
        let originalImage: UIImage? = nil  // 不预加载原图
        
        // 只在 asset 有 location 时赋值，否则为 nil
        var locationInfo: LocationInfo? = nil
        if let assetLocation = asset.location {
            print("📸 照片 \(photoId) 有地理坐标: \(assetLocation.coordinate.latitude), \(assetLocation.coordinate.longitude)")
            print("  - 精度: \(assetLocation.horizontalAccuracy) 米")
            print("  - 海拔: \(assetLocation.altitude) 米")
            print("  - 时间戳: \(assetLocation.timestamp)")
            
            locationInfo = LocationInfo(
                coordinate: assetLocation.coordinate,
                country: nil,
                state: nil,
                city: nil,
                address: nil
            )
            print("  - 创建了基础LocationInfo，等待地理编码...")
        } else {
            print("📸 照片 \(photoId) 没有地理坐标信息")
            // 如果照片没有地理信息，写入详细JSON到LOG.txt
            var dict: [String: Any] = [
                "id": photoId,
                "creationDate": creationDate.description,
                "mediaType": asset.mediaType.rawValue,
                "mediaSubtypes": asset.mediaSubtypes.rawValue,
                "sourceType": asset.sourceType.rawValue,
                "duration": asset.duration,
                "pixelWidth": asset.pixelWidth,
                "pixelHeight": asset.pixelHeight,
                "isFavorite": asset.isFavorite,
                "isHidden": asset.isHidden,
                "canEdit": asset.canPerform(.content),
                "location": asset.location?.description ?? "nil"
            ]
            if let loc = asset.location {
                dict["latitude"] = loc.coordinate.latitude
                dict["longitude"] = loc.coordinate.longitude
                dict["altitude"] = loc.altitude
                dict["accuracy"] = loc.horizontalAccuracy
                dict["timestamp"] = loc.timestamp.description
            }
            if let data = try? JSONSerialization.data(withJSONObject: dict, options: .prettyPrinted),
               let jsonString = String(data: data, encoding: .utf8) {
                appendLog("[无地理信息照片] " + jsonString)
            }
        }
        
        print("📸 照片元数据提取完成: \(photoId)")
        print("  - 拍摄时间: \(creationDate)")
        print("  - 尺寸: \(asset.pixelWidth) x \(asset.pixelHeight)")
        print("  - 是否有地理信息: \(asset.location != nil)")
        
        return PhotoData(
            id: photoId,
            creationDate: creationDate,
            location: locationInfo,
            thumbnail: thumbnail,
            originalImage: originalImage,
            asset: asset
        )
    }
    
    private func getThumbnail(for asset: PHAsset) async -> UIImage? {
        return await withCheckedContinuation { continuation in
            let options = PHImageRequestOptions()
            options.deliveryMode = .fastFormat
            options.isNetworkAccessAllowed = true
            options.isSynchronous = false
            
            // 进一步减少缩略图尺寸，降低内存占用
            PHImageManager.default().requestImage(
                for: asset,
                targetSize: CGSize(width: 100, height: 100), // 从150x150进一步减少到100x100
                contentMode: .aspectFill,
                options: options
            ) { image, _ in
                // 修复Alpha格式问题：转换为不透明格式
                if let image = image {
                    let renderer = UIGraphicsImageRenderer(size: image.size)
                    let fixedImage = renderer.image { context in
                        image.draw(in: CGRect(origin: .zero, size: image.size))
                    }
                    continuation.resume(returning: fixedImage)
                } else {
                    continuation.resume(returning: nil)
                }
            }
        }
    }
    
    private func getOriginalImage(for asset: PHAsset) async -> UIImage? {
        return await withCheckedContinuation { continuation in
            let options = PHImageRequestOptions()
            options.deliveryMode = .highQualityFormat
            options.isNetworkAccessAllowed = true
            options.isSynchronous = false
            
            // 进一步限制最大尺寸，避免内存溢出
            let maxSize = CGSize(width: 512, height: 512) // 从1024x1024减少到512x512
            
            PHImageManager.default().requestImage(
                for: asset,
                targetSize: maxSize,
                contentMode: .aspectFit,
                options: options
            ) { image, _ in
                // 修复Alpha格式问题：转换为不透明格式
                if let image = image {
                    // 检查图片尺寸，如果太大则压缩
                    let maxDimension: CGFloat = 512 // 从1024减少到512
                    let scale = min(maxDimension / image.size.width, maxDimension / image.size.height, 1.0)
                    
                    if scale < 1.0 {
                        let newSize = CGSize(width: image.size.width * scale, height: image.size.height * scale)
                        let renderer = UIGraphicsImageRenderer(size: newSize)
                        let compressedImage = renderer.image { context in
                            image.draw(in: CGRect(origin: .zero, size: newSize))
                        }
                        continuation.resume(returning: compressedImage)
                    } else {
                        let renderer = UIGraphicsImageRenderer(size: image.size)
                        let fixedImage = renderer.image { context in
                            image.draw(in: CGRect(origin: .zero, size: image.size))
                        }
                        continuation.resume(returning: fixedImage)
                    }
                } else {
                    continuation.resume(returning: nil)
                }
            }
        }
    }
    
    // MARK: - 地理编码处理
    
    private func geocodeCoordinate(_ coordinate: CLLocationCoordinate2D) async -> LocationInfo? {
        let coordinateKey = coordinateKey(coordinate)
        
        // 🚀 优化：检查地址缓存
        if let cachedLocationInfo = addressCache[coordinateKey] {
            cacheHitCount += 1
            
            // 检查缓存数据的完整性
            let hasAddress = cachedLocationInfo.address != nil && cachedLocationInfo.address != "未知"
            let hasCity = cachedLocationInfo.city != nil && cachedLocationInfo.city != "未知"
            let hasCountry = cachedLocationInfo.country != nil && cachedLocationInfo.country != "未知"
            
            if hasAddress && hasCity && hasCountry {
                let now = Date()
                let formatter = DateFormatter()
                formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
                let timestamp = formatter.string(from: now)
                print("[PhotoService.geocodeCoordinate] [\(timestamp)] 📍 缓存命中 [\(coordinateKey)] - 完整数据")
                return cachedLocationInfo.toLocationInfo()
            } else {
                let now = Date()
                let formatter = DateFormatter()
                formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
                let timestamp = formatter.string(from: now)
                print("[PhotoService.geocodeCoordinate] [\(timestamp)] 📍 缓存命中 [\(coordinateKey)] - 数据不完整，重新查询")
            }
        }
        
        cacheMissCount += 1
        apiCallCount += 1
        
        // 🚀 优化：使用信号量限制并发API调用
        return await withCheckedContinuation { continuation in
            geocodingQueue.async {
                self.geocodingSemaphore.wait()
                
                Task {
                    let (result, _) = await self.performGeocodingAPI(coordinate: coordinate, coordinateKey: coordinateKey)
                    self.geocodingSemaphore.signal()
                    continuation.resume(returning: result)
            }
        }
        }
    }
    
    // 🚀 新增：使用配置系统的地理编码API调用逻辑
    private func performGeocodingAPI(coordinate: CLLocationCoordinate2D, coordinateKey: String) async -> (LocationInfo?, GeocodingService?) {
        let now = Date()
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
        let timestamp = formatter.string(from: now)
        
        print("[PhotoService.performGeocodingAPI] [\(timestamp)] 📍 API调用 [\(coordinateKey)] - 坐标: \(coordinate.latitude), \(coordinate.longitude)")
        
        let config = GeocodingConfig.shared
        let availableServices = config.getAvailableServices()
        
        if availableServices.isEmpty {
            print("[PhotoService.performGeocodingAPI] [\(timestamp)] ❌ 没有可用的地理编码服务")
            return (nil, nil)
        }
        
        print("[PhotoService.performGeocodingAPI] [\(timestamp)] 📋 可用服务: \(availableServices.map { $0.displayName }.joined(separator: " → "))")
        
        // 按配置的优先级尝试各个服务
        for (index, service) in availableServices.enumerated() {
            let isLastService = index == availableServices.count - 1
            print("[PhotoService.performGeocodingAPI] [\(timestamp)] 🔍 尝试服务 \(index + 1)/\(availableServices.count): \(service.displayName)")
            
            if let locationInfo = await tryGeocodingService(service, coordinate: coordinate, coordinateKey: coordinateKey) {
                // 🚀 新增：解析成功后添加到已知地址
                addKnownAddress(coordinate: coordinate, locationInfo: locationInfo)
                return (locationInfo, service)
            } else if !isLastService {
                print("[PhotoService.performGeocodingAPI] [\(timestamp)] ❌ \(service.displayName) 失败，尝试下一个服务")
                // 添加延迟避免过快请求
                try? await Task.sleep(nanoseconds: UInt64(config.retryDelay * 1_000_000_000))
            } else {
                print("[PhotoService.performGeocodingAPI] [\(timestamp)] ❌ 所有地理编码服务都失败了")
            }
        }
        
        return (nil, nil)
    }
    
    // 🚀 新增：尝试单个地理编码服务
    private func tryGeocodingService(_ service: GeocodingService, coordinate: CLLocationCoordinate2D, coordinateKey: String) async -> LocationInfo? {
        switch service {
        case .apple:
            return await tryAppleGeocoding(coordinate: coordinate, coordinateKey: coordinateKey)
        case .google:
            return await tryGoogleGeocoding(coordinate: coordinate, coordinateKey: coordinateKey)
        case .amap:
            return await tryAMapGeocoding(coordinate: coordinate, coordinateKey: coordinateKey)
        case .openStreetMap:
            return await tryOpenStreetMapGeocoding(coordinate: coordinate, coordinateKey: coordinateKey)
        case .tencent:
            return await tryTencentGeocoding(coordinate: coordinate, coordinateKey: coordinateKey)
        }
    }
    
    // 🚀 新增：尝试Apple地理编码
    private func tryAppleGeocoding(coordinate: CLLocationCoordinate2D, coordinateKey: String) async -> LocationInfo? {
        let now = Date()
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
        let timestamp = formatter.string(from: now)
        
        print("[PhotoService.tryAppleGeocoding] [\(timestamp)] 🍎 尝试Apple地理编码: [\(coordinateKey)]")
        
        do {
            if let appleAddressInfo = await AppleGeocodingService.shared.fetchAddressInfoAsync(
                latitude: coordinate.latitude,
                longitude: coordinate.longitude
            ) {
                // 🎯 优先使用POI名称作为地址
                let address = appleAddressInfo.poiName ?? appleAddressInfo.displayName
                
                // 创建LocationInfo对象
                let locationInfo = LocationInfo(
                    coordinate: coordinate,
                    country: appleAddressInfo.country,
                    state: appleAddressInfo.administrativeArea,
                    city: appleAddressInfo.cityName,
                    address: address
                )
                
                // 保存到地址缓存
                let serializableLocationInfo = SerializableLocationInfo(from: locationInfo)
                addressCache[coordinateKey] = serializableLocationInfo
                saveAddressCache()
                
                // 🚀 新增：添加到已知地址
                addKnownAddress(coordinate: coordinate, locationInfo: locationInfo)
                
                print("[PhotoService.tryAppleGeocoding] [\(timestamp)] ✅ Apple地理编码成功 [\(coordinateKey)] - \(appleAddressInfo.cityName) - \(appleAddressInfo.displayName)")
                
                return locationInfo
            } else {
                print("[PhotoService.tryAppleGeocoding] [\(timestamp)] ❌ Apple地理编码失败 [\(coordinateKey)]")
                return nil
            }
        } catch {
            print("[PhotoService.tryAppleGeocoding] [\(timestamp)] ❌ Apple地理编码异常 [\(coordinateKey)]: \(error.localizedDescription)")
            return nil
        }
    }
    
    // 🚀 新增：尝试Google地理编码
    private func tryGoogleGeocoding(coordinate: CLLocationCoordinate2D, coordinateKey: String) async -> LocationInfo? {
        let now = Date()
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
        let timestamp = formatter.string(from: now)
        
        print("[PhotoService.tryGoogleGeocoding] [\(timestamp)] 🗺️ [Google] 尝试Google地理编码: [\(coordinateKey)]")
        
        do {
            if let googleAddressInfo = await GoogleMapsService.shared.reverseGeocode(coordinate: coordinate) {
                // 创建LocationInfo对象
                let locationInfo = LocationInfo(
                    coordinate: coordinate,
                    country: googleAddressInfo.country,
                    state: googleAddressInfo.province,
                    city: googleAddressInfo.city,
                    address: googleAddressInfo.displayName
                )
                
                // 保存到缓存
                let serializableLocationInfo = SerializableLocationInfo(from: locationInfo)
                addressCache[coordinateKey] = serializableLocationInfo
                saveAddressCache()
                
                // 🚀 新增：添加到已知地址
                addKnownAddress(coordinate: coordinate, locationInfo: locationInfo)
                
                print("[PhotoService.tryGoogleGeocoding] [\(timestamp)] ✅ Google地理编码成功 [\(coordinateKey)] - \(googleAddressInfo.displayName)")
                
                return locationInfo
            } else {
                print("[PhotoService.tryGoogleGeocoding] [\(timestamp)] ❌ Google地理编码失败 [\(coordinateKey)]")
                return nil
            }
        } catch {
            print("[PhotoService.tryGoogleGeocoding] [\(timestamp)] ❌ Google地理编码异常 [\(coordinateKey)]: \(error.localizedDescription)")
            return nil
        }
    }
    
    // 🚀 新增：尝试OpenStreetMap地理编码
    private func tryOpenStreetMapGeocoding(coordinate: CLLocationCoordinate2D, coordinateKey: String) async -> LocationInfo? {
        let startTime = Date()
        let now = Date()
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
        let timestamp = formatter.string(from: now)
        
        print("[PhotoService.tryOpenStreetMapGeocoding] [\(timestamp)] 🌍 [OSM] 开始OpenStreetMap地理编码: [\(coordinateKey)]")
        print("[PhotoService.tryOpenStreetMapGeocoding] [\(timestamp)] 🌍 [OSM] 坐标详情: 纬度=\(coordinate.latitude), 经度=\(coordinate.longitude)")
        
        do {
            print("[PhotoService.tryOpenStreetMapGeocoding] [\(timestamp)] 🌍 [OSM] 调用OpenStreetMapService.reverseGeocode...")
            if let osmAddressInfo = await OpenStreetMapService.shared.reverseGeocode(coordinate: coordinate) {
                let endTime = Date()
                let duration = endTime.timeIntervalSince(startTime)
                print("[PhotoService.tryOpenStreetMapGeocoding] [\(timestamp)] 🌍 [OSM] 服务调用成功，耗时: \(String(format: "%.2f", duration))秒")
                
                // 创建LocationInfo对象
                let locationInfo = LocationInfo(
                    coordinate: coordinate,
                    country: osmAddressInfo.country,
                    state: osmAddressInfo.province,
                    city: osmAddressInfo.city,
                    address: osmAddressInfo.displayName
                )
                
                // 保存到缓存
                let serializableLocationInfo = SerializableLocationInfo(from: locationInfo)
                addressCache[coordinateKey] = serializableLocationInfo
                saveAddressCache()
                
                // 🚀 新增：添加到已知地址
                addKnownAddress(coordinate: coordinate, locationInfo: locationInfo)
                
                print("[PhotoService.tryOpenStreetMapGeocoding] [\(timestamp)] 🌍 [OSM] ✅ 成功: [\(coordinateKey)] -> \(osmAddressInfo.displayName)")
                
                return locationInfo
            } else {
                let endTime = Date()
                let duration = endTime.timeIntervalSince(startTime)
                print("[PhotoService.tryOpenStreetMapGeocoding] [\(timestamp)] 🌍 [OSM] ❌ 失败: [\(coordinateKey)] - 无返回结果 (耗时: \(String(format: "%.2f", duration))秒)")
                return nil
            }
        } catch {
            let endTime = Date()
            let duration = endTime.timeIntervalSince(startTime)
            print("[PhotoService.tryOpenStreetMapGeocoding] [\(timestamp)] 🌍 [OSM] ❌ 异常: [\(coordinateKey)] - \(error.localizedDescription) (耗时: \(String(format: "%.2f", duration))秒)")
            return nil
        }
    }
    
    // 🚀 新增：尝试高德地图地理编码
    private func tryAMapGeocoding(coordinate: CLLocationCoordinate2D, coordinateKey: String) async -> LocationInfo? {
        let now = Date()
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
        let timestamp = formatter.string(from: now)
        
        print("[PhotoService.tryAMapGeocoding] [\(timestamp)] 🗺️ 尝试高德地图API: [\(coordinateKey)]")
        
        if let addressInfo = await AMapService.shared.fetchAddressInfoAsync(coordinate: coordinate) {
            // 检查API返回数据的完整性
            let hasCountry = addressInfo.country != nil && !addressInfo.country!.isEmpty && addressInfo.country! != "未知"
            let hasCity = addressInfo.city != nil && !addressInfo.city!.isEmpty && addressInfo.city! != "未知"
            let hasAddress = addressInfo.poiName != nil || (addressInfo.formattedAddress != nil && !addressInfo.formattedAddress!.isEmpty)
            
            // 🎯 优先使用POI名称作为地址
            let address = addressInfo.poiName ?? addressInfo.formattedAddress ?? "未知地点"
            let locationInfo = LocationInfo(
                coordinate: coordinate,
                country: addressInfo.country,
                state: addressInfo.province,
                city: addressInfo.city,
                address: address
            )
            
            // 保存到地址缓存
            let serializableLocationInfo = SerializableLocationInfo(from: locationInfo)
            addressCache[coordinateKey] = serializableLocationInfo
            saveAddressCache()
            
            // 🚀 新增：添加到已知地址
            addKnownAddress(coordinate: coordinate, locationInfo: locationInfo)
            
            if hasCountry && hasCity && hasAddress {
                print("[PhotoService.tryAMapGeocoding] [\(timestamp)] ✅ 高德地图API成功 [\(coordinateKey)] - 完整数据")
            } else {
                print("[PhotoService.tryAMapGeocoding] [\(timestamp)] ✅ 高德地图API成功 [\(coordinateKey)] - 部分数据")
            }
            
            return locationInfo
        } else {
            print("[PhotoService.tryAMapGeocoding] [\(timestamp)] ❌ 高德地图API失败 [\(coordinateKey)]")
            return nil
        }
    }
    
    // 🚀 新增：尝试腾讯地图地理编码
    private func tryTencentGeocoding(coordinate: CLLocationCoordinate2D, coordinateKey: String) async -> LocationInfo? {
        let now = Date()
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
        let timestamp = formatter.string(from: now)
        
        print("[PhotoService.tryTencentGeocoding] [\(timestamp)] 🗺️ 尝试腾讯地图API: [\(coordinateKey)]")
        
        if let addressInfo = await TencentMapsService.shared.fetchAddressInfoAsync(coordinate: coordinate) {
            // 检查API返回数据的完整性
            let hasCountry = addressInfo.country != nil && !addressInfo.country!.isEmpty && addressInfo.country! != "未知"
            let hasCity = addressInfo.city != nil && !addressInfo.city!.isEmpty && addressInfo.city! != "未知"
            let hasAddress = addressInfo.poiName != nil || (addressInfo.formattedAddress != nil && !addressInfo.formattedAddress!.isEmpty)
            
            // 🎯 优先使用POI名称作为地址
            let address = addressInfo.poiName ?? addressInfo.formattedAddress ?? "未知地点"
            let locationInfo = LocationInfo(
                coordinate: coordinate,
                country: addressInfo.country,
                state: addressInfo.province,
                city: addressInfo.city,
                address: address
            )
            
            // 保存到地址缓存
            let serializableLocationInfo = SerializableLocationInfo(from: locationInfo)
            addressCache[coordinateKey] = serializableLocationInfo
            saveAddressCache()
            
            // 🚀 新增：添加到已知地址
            addKnownAddress(coordinate: coordinate, locationInfo: locationInfo)
            
            if hasCountry && hasCity && hasAddress {
                print("[PhotoService.tryTencentGeocoding] [\(timestamp)] ✅ 腾讯地图API成功 [\(coordinateKey)] - 完整数据")
            } else {
                print("[PhotoService.tryTencentGeocoding] [\(timestamp)] ✅ 腾讯地图API成功 [\(coordinateKey)] - 部分数据")
            }
            
            return locationInfo
        } else {
            print("[PhotoService.tryTencentGeocoding] [\(timestamp)] ❌ 腾讯地图API失败 [\(coordinateKey)]")
            return nil
        }
    }
    
    private func appendLog(_ text: String) {
        let logURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].appendingPathComponent("LOG.txt")
        if let handle = try? FileHandle(forWritingTo: logURL) {
            handle.seekToEndOfFile()
            if let data = (text + "\n").data(using: .utf8) {
                handle.write(data)
            }
            handle.closeFile()
        } else {
            // 文件不存在则创建
            try? (text + "\n").write(to: logURL, atomically: true, encoding: .utf8)
        }
    }
    
    // MARK: - 缓存管理
    
    private func getCacheFilePath() -> URL {
        let documentsPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
        return documentsPath.appendingPathComponent(cacheFileName)
    }
    
    /// 清除所有缓存数据
    func clearAllCache() {
        // 清除照片缓存文件
        let cachePath = getCacheFilePath()
        try? FileManager.default.removeItem(at: cachePath)
        
        // 清除地址缓存
        UserDefaults.standard.removeObject(forKey: addressCacheKey)
        addressCache.removeAll()
        
        // 清除已处理照片ID
        UserDefaults.standard.removeObject(forKey: processedPhotosKey)
        processedPhotoIds.removeAll()
        
        // 清除持久化数据映射
        UserDefaults.standard.removeObject(forKey: photoDataMapKey)
        photoDataMap.removeAll()
        
        // 清除内存缓存
        locationCache.removeAll()
        photos.removeAll()
        
        // 清除分组缓存
        cachedLocationGroups.removeAll()
        lastPhotoCount = 0
        
        // 🚀 新增：清除数据指纹
        lastDataFingerprint = ""
        
        // 🚀 新增：清除地点轴分组持久化数据
        UserDefaults.standard.removeObject(forKey: locationGroupsKey)
        
        print("🗑️ 已清除所有缓存数据，包括持久化数据映射、地点轴分组和数据指纹")
    }
    
    /// 清除照片缓存但保留地址缓存
    func clearPhotoCache() {
        // 清除照片缓存文件
        let cachePath = getCacheFilePath()
        try? FileManager.default.removeItem(at: cachePath)
        
        // 清除已处理照片ID
        UserDefaults.standard.removeObject(forKey: processedPhotosKey)
        processedPhotoIds.removeAll()
        
        // 清除内存中的照片
        photos.removeAll()
        
        print("🗑️ 已清除照片缓存，保留地址缓存")
    }
    
    // MARK: - 照片加载和地理编码
    
    func loadAllPhotos() async {
        let startTime = Date()
        print("🟢 开始加载照片... - \(startTime)")
        
        await MainActor.run {
            isLoading = true
            errorMessage = nil
        }
        
        // 检查权限
        checkAuthorizationStatus()
        guard authorizationStatus == .authorized || authorizationStatus == .limited else {
            await MainActor.run {
                isLoading = false
                errorMessage = "需要相册访问权限"
            }
            return
        }
        
        // 获取本机总照片数
        await getTotalPhotoCount()
        
        // 🚀 优化：优先使用快速开机加载
        if !photoDataMap.isEmpty {
            print("📂 尝试快速开机加载，映射中有 \(photoDataMap.count) 条记录")
            
            // 尝试快速加载
            let fastLoadSuccess = await fastLoadFromPersistentData()
            if fastLoadSuccess {
                let endTime = Date()
                let duration = endTime.timeIntervalSince(startTime)
                print("🚀 快速开机加载成功，共 \(photos.count) 张照片")
                print("⏱️ 快速加载耗时: \(String(format: "%.2f", duration)) 秒")
                await MainActor.run {
                    isLoading = false
                }
                return
            }
            
            // 如果快速加载失败，回退到原来的加载方式
            print("📂 快速加载失败，回退到标准加载方式")
            await loadPhotosFromPersistentData()
            
            print("📂 loadAllPhotos检查: photos数组大小 = \(photos.count)")
            
            // 如果持久化数据加载成功，直接返回
            if photos.count > 0 {
                print("📂 持久化数据加载成功，共 \(photos.count) 张照片")
                await MainActor.run {
                    isLoading = false
                }
                return
            }
        }
        
        // 🚀 修复：如果持久化数据为空或加载失败，从相册重新加载
        print("📂 持久化数据为空或加载失败，从相册重新加载...")
        await loadPhotosFromLibrary()
        
        print("📂 loadAllPhotos检查: photos数组大小 = \(photos.count)")
        
        // 🚀 修复：验证照片加载完整性
        if photos.count != totalPhotoCount {
            print("⚠️ 照片加载不完整: 期望 \(totalPhotoCount) 张，实际 \(photos.count) 张")
            print("🔄 尝试重新加载缺失的照片...")
            await reloadMissingPhotos()
        }
        
        // 🚀 修改：禁止自动地理编码，优先显示所有照片
        if !photos.isEmpty {
            print("📍 照片加载完成，共 \(photos.count) 张照片")
            print("📍 禁止自动地理编码，用户需手动触发")
            
            // 统计需要地理编码的照片数量
            let photosNeedingGeocoding = photos.filter { photo in
                guard let location = photo.location else { return false }
                let hasAddress = location.address != nil && location.address != "未知"
                let hasCity = location.city != nil && location.city != "未知"
                let hasCountry = location.country != nil && location.country != "未知"
                return !hasAddress || !hasCity || !hasCountry
            }
            
            print("📍 统计：\(photosNeedingGeocoding.count) 张照片需要地理编码")
        }
        
        let endTime = Date()
        let duration = endTime.timeIntervalSince(startTime)
        print("⏱️ 标准加载耗时: \(String(format: "%.2f", duration)) 秒")
        
        // 加载完成后检查功能E
        checkFunctionE()
        
        // 🚀 新增：显示缓存统计和性能报告
        await showCacheStatistics()
        generateOptimizationReport()
        cleanupExpiredCache()
        
        // 🚀 新增：打印未能解析成功的照片信息（在主线程安全执行）
        await MainActor.run {
            // 🚀 新增：在调用前检查photos数组状态
            print("🔍 [调用前检查] photos数组大小: \(self.photos.count)")
            print("🔍 [调用前检查] photos数组是否为空: \(self.photos.isEmpty)")
            
            if !self.photos.isEmpty {
                self.printUnresolvedPhotosInfo()
            } else {
                print("⚠️ [调用前检查] photos数组为空，跳过printUnresolvedPhotosInfo调用")
            }
        }
    }
    
    // 🚀 新增：重新加载缺失的照片
    private func reloadMissingPhotos() async {
        print("🔄 开始重新加载缺失的照片...")
        
        let fetchResult = PHAsset.fetchAssets(with: .image, options: nil)
        let totalCount = fetchResult.count
        print("🔄 相册照片总数: \(totalCount) 张")
        
        var missingPhotos: [PhotoData] = []
        var processedCount = 0
        
        // 检查哪些照片没有被加载
        for i in 0..<totalCount {
            let asset = fetchResult.object(at: i)
            let photoId = asset.localIdentifier
            
            // 检查是否已经加载
            if !photos.contains(where: { $0.id == photoId }) {
                if let photoData = await extractPhotoData(from: asset) {
                    missingPhotos.append(photoData)
                    processedCount += 1
                    
                    // 更新持久化数据映射
                    updatePhotoDataInMap(photoId, photoData)
                }
            }
            
            // 每处理100张照片更新一次进度
            if processedCount % 100 == 0 {
                print("🔄 已处理 \(processedCount) 张缺失照片...")
            }
        }
        
        print("🔄 找到 \(missingPhotos.count) 张缺失的照片")
        
        if !missingPhotos.isEmpty {
            await MainActor.run {
                self.photos.append(contentsOf: missingPhotos)
                print("🔄 照片数组更新完成，现在共有 \(self.photos.count) 张照片")
            }
            
            // 保存更新后的数据映射
            savePhotoDataMap()
        }
    }
    
    // 🚀 新增：立即开始地理编码
    private func startImmediateGeocoding() async {
        let photosNeedingGeocoding = photos.filter { photo in
            guard let location = photo.location else { return false }
            let hasAddress = location.address != nil && location.address != "未知"
            let hasCity = location.city != nil && location.city != "未知"
            let hasCountry = location.country != nil && location.country != "未知"
            return !hasAddress || !hasCity || !hasCountry
        }
        
        if !photosNeedingGeocoding.isEmpty {
            print("📍 发现 \(photosNeedingGeocoding.count) 张照片需要地理编码，立即开始...")
            await performGeocoding(for: photosNeedingGeocoding)
        } else {
            print("📍 所有照片地址信息完整，无需地理编码")
        }
    }
    
    // 🚀 新增：显示缓存统计（简化版）
    private func showCacheStatistics() async {
        let stats = getCacheStats()
        let hitRate = stats.hits + stats.misses > 0 ? Double(stats.hits) / Double(stats.hits + stats.misses) * 100 : 0
        print("📊 缓存统计: 命中率 \(String(format: "%.1f", hitRate))%, 缓存大小 \(stats.totalCache) 条")
    }
    
    private func loadPhotosFromPersistentData() async {
        let standardLoadStartTime = Date()
        print("📂 开始标准加载 - \(standardLoadStartTime)")
        
        guard !photoDataMap.isEmpty else {
            print("📂 持久化数据映射为空")
            return
        }
        
        print("📂 开始从持久化数据加载照片，映射中有 \(photoDataMap.count) 条记录")
        
        var loadedPhotos: [PhotoData] = []
        var validCount = 0
        var invalidCount = 0
        
        let photoIds = Array(photoDataMap.keys)
        let batchSize = 50
        
        print("📂 开始处理 \(photoIds.count) 个照片ID")
        
        for i in stride(from: 0, to: photoIds.count, by: batchSize) {
            let endIndex = min(i + batchSize, photoIds.count)
            let batchIds = Array(photoIds[i..<endIndex])
            
            let fetchResult = PHAsset.fetchAssets(withLocalIdentifiers: batchIds, options: nil)
            let existingAssets = fetchResult.objects(at: IndexSet(0..<fetchResult.count))
            
                            // 🚀 性能优化：减少开机批次日志，只在调试模式或大量照片时打印
                #if DEBUG
                if photos.count > 1000 {
                    print("📂 批次 \(i/batchSize + 1): 处理 \(batchIds.count) 个ID，找到 \(existingAssets.count) 个资产")
                }
                #endif
            
            for photoId in batchIds {
                if let asset = existingAssets.first(where: { $0.localIdentifier == photoId }),
                   let serializableData = photoDataMap[photoId] {
                    let photoData = serializableData.toPhotoData(asset: asset)
                    loadedPhotos.append(photoData)
                    validCount += 1
                } else {
                    invalidCount += 1
                    photoDataMap.removeValue(forKey: photoId)
                }
            }
            
            // 🚀 修改：更频繁地更新UI，确保数据同步
            if i % batchSize == 0 {
                await MainActor.run {
                    self.photos = loadedPhotos
                    // 🚀 性能优化：减少开机中间更新日志，只在调试模式或大量照片时打印
                #if DEBUG
                if photos.count > 1000 {
                    print("📂 中间更新: photos数组现在有 \(self.photos.count) 张照片")
                }
                #endif
                }
            }
        }
        
        let standardLoadEndTime = Date()
        let standardLoadDuration = standardLoadEndTime.timeIntervalSince(standardLoadStartTime)
        print("📂 持久化数据加载完成: \(validCount) 张有效照片，\(invalidCount) 张无效")
        print("📂 loadedPhotos数组大小: \(loadedPhotos.count)")
        print("⏱️ 标准加载内部耗时: \(String(format: "%.2f", standardLoadDuration)) 秒")
        
        if !loadedPhotos.isEmpty {
            await MainActor.run {
                self.photos = loadedPhotos
                print("📂 最终赋值: photos数组现在有 \(self.photos.count) 张照片")
                
                // 🚀 新增：验证赋值是否成功
                if self.photos.count != loadedPhotos.count {
                    print("⚠️ [验证失败] photos数组赋值后大小不匹配: 期望 \(loadedPhotos.count), 实际 \(self.photos.count)")
                } else {
                    print("✅ [验证成功] photos数组赋值成功")
                }
                
                // 🚀 新增：强制刷新UI
                self.objectWillChange.send()
            }
        } else {
            print("⚠️ loadedPhotos数组为空，无法赋值给photos")
        }
    }
    
    // MARK: - 增量更新管理
    
    private func loadProcessedPhotoIds() {
        if let data = UserDefaults.standard.data(forKey: processedPhotosKey),
           let ids = try? JSONDecoder().decode(Set<String>.self, from: data) {
            processedPhotoIds = ids
            print("📋 已处理照片ID加载成功: \(ids.count) 个")
        } else {
            print("📋 已处理照片ID为空，将创建新记录")
        }
    }
    
    private func saveProcessedPhotoIds() {
        if let data = try? JSONEncoder().encode(processedPhotoIds) {
            UserDefaults.standard.set(data, forKey: processedPhotosKey)
        }
    }
    
    private func isPhotoProcessed(photoId: String) -> Bool {
        return processedPhotoIds.contains(photoId)
    }
    
    private func markPhotoAsProcessed(photoId: String) {
        processedPhotoIds.insert(photoId)
        saveProcessedPhotoIds()
    }
    
    // MARK: - 持久化状态检查
    
    /// 检查本地持久化状态
    func checkPersistenceStatus() {
        let cachePath = getCacheFilePath()
        let fileExists = FileManager.default.fileExists(atPath: cachePath.path)
        
        print("🔍 === 持久化状态检查 ===")
        print("🔍 缓存文件存在: \(fileExists)")
        
        if fileExists {
            do {
                let attributes = try FileManager.default.attributesOfItem(atPath: cachePath.path)
                let fileSize = attributes[.size] as? Int64 ?? 0
                let modificationDate = attributes[.modificationDate] as? Date ?? Date()
                
                print("🔍 缓存文件大小: \(fileSize) 字节")
                print("🔍 最后修改时间: \(modificationDate)")
                
                // 尝试读取缓存数据
                let data = try Data(contentsOf: cachePath)
                let decoder = JSONDecoder()
                decoder.dateDecodingStrategy = .iso8601
                let serializablePhotos = try decoder.decode([SerializablePhotoData].self, from: data)
                
                print("🔍 缓存中的照片数量: \(serializablePhotos.count)")
                
                // 检查地址缓存
                if let addressData = UserDefaults.standard.data(forKey: addressCacheKey),
                   let addressDict = try? JSONDecoder().decode([String: SerializableLocationInfo].self, from: addressData) {
                    print("🔍 地址缓存数量: \(addressDict.count)")
                } else {
                    print("🔍 地址缓存为空")
                }
                
                // 检查已处理照片ID
                if let processedData = UserDefaults.standard.data(forKey: processedPhotosKey),
                   let processedIds = try? JSONDecoder().decode(Set<String>.self, from: processedData) {
                    print("🔍 已处理照片ID数量: \(processedIds.count)")
                } else {
                    print("🔍 已处理照片ID为空")
                }
                
            } catch {
                print("❌ 缓存文件读取失败: \(error.localizedDescription)")
            }
        }
        
        print("🔍 当前内存中的照片数量: \(photos.count)")
        print("🔍 === 持久化状态检查完成 ===")
    }
    
    // MARK: - 地点分组
    
    // 🚀 优化：添加缓存机制
    private var cachedLocationGroups: [LocationGroup] = []
    private var lastPhotoCount = 0
    
    // 🚀 新增：地点轴分组持久化（旧版本，已废弃）
    private let locationGroupsKey = "LocationGroups_Old"
    
    // 🚀 新增：缓存数据指纹，用于检测照片内容变化
    private var lastDataFingerprint: String = ""
    
    // 🚀 新增：计算照片数据指纹
    private func calculateDataFingerprint() -> String {
        var fingerprint = "\(photos.count)_"
        
        // 统计有地理信息的照片
        let photosWithLocation = photos.filter { $0.location != nil }
        fingerprint += "\(photosWithLocation.count)_"
        
        // 统计未知地址的照片
        let unknownAddressPhotos = photosWithLocation.filter { photo in
            guard let location = photo.location else { return false }
            let hasAddress = location.address != nil && location.address != "未知" && location.address != "未知地点"
            let hasCity = location.city != nil && location.city != "未知" && location.city != "未知城市"
            let hasCountry = location.country != nil && location.country != "未知" && location.country != "未知国家"
            return !hasAddress || !hasCity || !hasCountry
        }
        fingerprint += "\(unknownAddressPhotos.count)_"
        
        // 统计已知地址的照片
        let knownAddressPhotos = photosWithLocation.filter { photo in
            guard let location = photo.location else { return false }
            let hasAddress = location.address != nil && location.address != "未知" && location.address != "未知地点"
            let hasCity = location.city != nil && location.city != "未知" && location.city != "未知城市"
            let hasCountry = location.country != nil && location.country != "未知" && location.country != "未知国家"
            return hasAddress && hasCity && hasCountry
        }
        fingerprint += "\(knownAddressPhotos.count)"
        
        return fingerprint
    }
    
    private func saveLocationGroups(_ groups: [LocationGroup]) {
        // 将LocationGroup转换为可序列化的格式
        let serializableGroups = groups.map { group in
            [
                "id": group.id,
                "country": group.country,
                "city": group.city,
                "detailedLocation": group.detailedLocation ?? "",
                "totalPhotos": group.totalPhotos,
                "isParentNode": group.isParentNode,
                "parentCity": group.parentCity ?? ""
            ]
        }
        
        if let data = try? JSONSerialization.data(withJSONObject: serializableGroups) {
            UserDefaults.standard.set(data, forKey: locationGroupsKey)
            print("🔍 [地点轴分组] 💾 地点轴分组已保存: \(groups.count) 个分组")
        } else {
            print("🔍 [地点轴分组] ❌ 地点轴分组保存失败")
        }
    }
    
    private func loadLocationGroups() -> [LocationGroup] {
        guard let data = UserDefaults.standard.data(forKey: locationGroupsKey),
              let serializableGroups = try? JSONSerialization.jsonObject(with: data) as? [[String: Any]] else {
            print("🔍 [地点轴分组] 📂 地点轴分组为空，将重新计算")
            return []
        }
        
        print("🔍 [地点轴分组] 📂 地点轴分组加载成功: \(serializableGroups.count) 个分组")
        
        // 🚀 修复：将序列化数据转换回LocationGroup
        var loadedGroups: [LocationGroup] = []
        
        for groupData in serializableGroups {
            guard let id = groupData["id"] as? String,
                  let country = groupData["country"] as? String,
                  let city = groupData["city"] as? String,
                  let totalPhotos = groupData["totalPhotos"] as? Int,
                  let isParentNode = groupData["isParentNode"] as? Bool else {
                print("🔍 [地点轴分组] ⚠️ 跳过无效的分组数据")
                continue
            }
            
            let detailedLocation = groupData["detailedLocation"] as? String
            let parentCity = groupData["parentCity"] as? String
            
            // 创建简化的LocationGroup（不包含照片数组，因为照片数据会重新加载）
            let locationGroup = LocationGroup(
                country: country,
                city: city,
                detailedLocation: detailedLocation?.isEmpty == false ? detailedLocation : nil,
                photos: [], // 照片数组会在groupPhotosByLocation中重新填充
                coverPhoto: nil, // 封面照片会在重新计算时生成
                totalPhotos: totalPhotos,
                isParentNode: isParentNode,
                parentCity: parentCity?.isEmpty == false ? parentCity : nil
            )
            
            loadedGroups.append(locationGroup)
        }
        
        print("🔍 [地点轴分组] 📂 成功加载 \(loadedGroups.count) 个分组结构")
        return loadedGroups
    }
    
    // 🚀 新增：将照片数据填充到分组结构中
    private func fillPhotosIntoGroups(_ groups: [LocationGroup]) -> [LocationGroup] {
        var filledGroups: [LocationGroup] = []
        
        print("🔍 [地点轴分组] 开始填充照片数据，总照片数: \(photos.count)")
        
        for group in groups {
            var photosInGroup: [PhotoData] = []
            
            // 根据分组信息匹配照片
            for photo in photos {
                guard let location = photo.location else { continue }
                
                let photoCountry = location.country ?? "未知国家"
                let photoCity = location.city ?? location.state ?? "未知城市"
                let photoDetailedLocation = location.address ?? "未知地点"
                
                // 🚀 修复：改进匹配逻辑
                let isMatch: Bool
                
                if group.isParentNode {
                    // 父节点匹配：国家和城市都匹配
                    isMatch = group.country == photoCountry && group.city == photoCity
                } else {
                    // 子节点匹配：国家、城市和详细地址都匹配
                    isMatch = group.country == photoCountry && 
                             group.city == photoCity && 
                             group.detailedLocation == photoDetailedLocation
                }
                
                if isMatch {
                    photosInGroup.append(photo)
                    // 注释掉刷屏的日志
                    // print("🔍 [地点轴分组] 匹配照片: \(photo.id) -> \(group.city)\(group.detailedLocation != nil ? " - \(group.detailedLocation!)" : "")")
                }
            }
            
            // 创建新的分组，包含照片数据
            let filledGroup = LocationGroup(
                country: group.country,
                city: group.city,
                detailedLocation: group.detailedLocation,
                photos: photosInGroup.sorted { $0.creationDate > $1.creationDate },
                coverPhoto: photosInGroup.first?.thumbnail,
                totalPhotos: photosInGroup.count,
                isParentNode: group.isParentNode,
                parentCity: group.parentCity
            )
            
            filledGroups.append(filledGroup)
            
            // 调试输出
            if photosInGroup.count > 0 {
                // 注释掉刷屏的日志
                // print("🔍 [地点轴分组] 分组 \(group.city)\(group.detailedLocation != nil ? " - \(group.detailedLocation!)" : "") 匹配到 \(photosInGroup.count) 张照片")
            }
        }
        
        print("🔍 [地点轴分组] 成功填充照片数据到 \(filledGroups.count) 个分组")
        return filledGroups
    }
    
    func groupPhotosByLocation() -> [LocationGroup] {
        print("🔍 [地点轴分组] === 开始分组计算 ===")
        print("🔍 [地点轴分组] 调用时间: \(Date())")
        print("🔍 [地点轴分组] photos数组大小: \(photos.count)")
        print("🔍 [地点轴分组] lastPhotoCount: \(lastPhotoCount)")
        print("🔍 [地点轴分组] cachedLocationGroups.isEmpty: \(cachedLocationGroups.isEmpty)")
        
        // 🚀 新增：计算当前数据指纹
        let currentFingerprint = calculateDataFingerprint()
        print("🔍 [地点轴分组] 当前数据指纹: \(currentFingerprint)")
        print("🔍 [地点轴分组] 上次数据指纹: \(lastDataFingerprint)")
        
            // 🚀 修复：开机优先使用持久化数据，但需要检查数据是否最新
    if cachedLocationGroups.isEmpty && photos.count > 0 {
        print("🔍 [地点轴分组] 尝试加载持久化分组数据...")
        let savedGroups = loadLocationGroups()
        if !savedGroups.isEmpty {
            print("🔍 [地点轴分组] 成功加载持久化分组数据: \(savedGroups.count) 个分组")
            
            // 🚀 新增：检查持久化数据是否包含所有照片
            let savedPhotoCount = savedGroups.reduce(0) { $0 + $1.totalPhotos }
            let currentPhotoCount = photos.count
            
            print("🔍 [地点轴分组] 持久化数据照片数: \(savedPhotoCount), 当前照片数: \(currentPhotoCount)")
            
            // 如果持久化数据不完整，强制重新计算
            if savedPhotoCount < currentPhotoCount {
                print("🔍 [地点轴分组] 持久化数据不完整，强制重新计算")
                // 清除缓存，强制重新计算
                cachedLocationGroups = []
                lastPhotoCount = 0
                lastDataFingerprint = ""
            } else {
                // 重新填充照片数据
                let filledGroups = fillPhotosIntoGroups(savedGroups)
                cachedLocationGroups = filledGroups
                lastPhotoCount = photos.count
                lastDataFingerprint = currentFingerprint
                return filledGroups
            }
        }
    }
        
            // 🚀 修复：使用数据指纹判断是否需要重新计算
    if lastPhotoCount == photos.count && !cachedLocationGroups.isEmpty && currentFingerprint == lastDataFingerprint {
        print("🔍 [地点轴分组] 数据指纹未变化，使用缓存结果，跳过重新计算")
        
        // 🚀 新增：检查是否有新解析的照片需要更新
        let hasNewGeocodedPhotos = photos.contains { photo in
            photo.location != nil && photo.location?.address != nil && 
            !cachedLocationGroups.contains { group in
                group.photos.contains { $0.id == photo.id }
            }
        }
        
        if hasNewGeocodedPhotos {
            print("🔍 [地点轴分组] 发现新解析的照片，强制重新计算")
            // 清除缓存，强制重新计算
            cachedLocationGroups = []
            lastPhotoCount = 0
            lastDataFingerprint = ""
        } else {
            return cachedLocationGroups
        }
    } else if currentFingerprint != lastDataFingerprint {
        print("🔍 [地点轴分组] 数据指纹发生变化，强制重新计算")
    }
        
        // 🚀 修复：更新照片数量记录（移到这里，避免在缓存命中时被重置）
        lastPhotoCount = photos.count
        let photosWithLocation = photos.filter { $0.location != nil }
        let photosWithoutLocation = photos.filter { $0.location == nil }
        
        // 🔍 调试：显示分组统计信息
        print("🔍 [地点轴分组] 总照片数: \(photos.count), 有地理信息的照片: \(photosWithLocation.count), 无地理信息的照片: \(photosWithoutLocation.count)")
        
        // 🚀 修复：处理所有照片，包括没有地理信息的照片
        var locationGroups: [LocationGroup] = []
        
        // 1. 处理有地理信息的照片
        if !photosWithLocation.isEmpty {
            // 按国家分组
            let countryGroups = Dictionary(grouping: photosWithLocation) { photo in
                if let location = photo.location {
                    return location.country ?? "未知国家"
                } else {
                    return "待地理编码"
                }
            }
            
            print("🔍 [地点轴分组] 国家分组结果: \(countryGroups.keys.sorted())")
            print("🔍 [地点轴分组] 国家分组数量: \(countryGroups.count)")
            
            for (country, countryPhotos) in countryGroups {
                // 注释掉刷屏的日志
                // print("🔍 [地点轴分组] 处理国家: \(country), 照片数: \(countryPhotos.count)")
                
                // 按城市分组
                let cityGroups = Dictionary(grouping: countryPhotos) { photo in
                    if let location = photo.location {
                        return location.city ?? location.state ?? "未知城市"
                    } else {
                        return "待地理编码"
                    }
                }
                
                print("🔍 [地点轴分组] 国家 \(country) 的城市分组: \(cityGroups.keys.sorted())")
                
                for (city, cityPhotos) in cityGroups {
                    // 注释掉刷屏的日志
                    // print("🔍 [地点轴分组] 处理城市: \(city), 照片数: \(cityPhotos.count)")
                    
                    // 按详细地址分组（如餐厅、景点等）
                    let detailedGroups = groupPhotosByDetailedLocation(cityPhotos)
                    
                    // 为每个城市创建一个父节点，包含该城市的所有照片
                    let allCityPhotos = cityPhotos.sorted { $0.creationDate > $1.creationDate }
                    let cityCoverPhoto = allCityPhotos.first?.thumbnail
                    
                    // 创建城市父节点
                    let cityGroup = LocationGroup(
                        country: country,
                        city: city,
                        detailedLocation: nil, // 父节点不显示详细地址
                        photos: allCityPhotos,
                        coverPhoto: cityCoverPhoto,
                        totalPhotos: allCityPhotos.count,
                        isParentNode: true, // 标记为父节点
                        parentCity: nil // 父节点没有父城市
                    )
                    locationGroups.append(cityGroup)
                    // 注释掉刷屏的日志
                    // print("🔍 [地点轴分组] 添加父节点: \(city) [\(allCityPhotos.count)张]")
                    
                    // 为每个详细地址创建子节点
                    for (detailedLocation, detailedPhotos) in detailedGroups {
                        let locationGroup = LocationGroup(
                            country: country,
                            city: city,
                            detailedLocation: detailedLocation,
                            photos: detailedPhotos.sorted { $0.creationDate > $1.creationDate },
                            coverPhoto: detailedPhotos.first?.thumbnail,
                            totalPhotos: detailedPhotos.count,
                            isParentNode: false, // 标记为子节点
                            parentCity: city // 关联到父城市
                        )
                        locationGroups.append(locationGroup)
                        // 注释掉刷屏的日志
                        // print("🔍 [地点轴分组] 添加子节点: \(detailedLocation) [\(detailedPhotos.count)张]")
                    }
                }
            }
        }
        
        // 2. 处理没有地理信息的照片
        if !photosWithoutLocation.isEmpty {
            print("🔍 [地点轴分组] 处理无地理信息的照片: \(photosWithoutLocation.count) 张")
            
            // 按时间分组（每月一组）
            let timeGroups = Dictionary(grouping: photosWithoutLocation) { photo in
                let formatter = DateFormatter()
                formatter.dateFormat = "yyyy年MM月"
                return formatter.string(from: photo.creationDate)
            }
            
            for (timeGroup, timePhotos) in timeGroups {
                let locationGroup = LocationGroup(
                    country: "待地理编码",
                    city: "未知城市",
                    detailedLocation: timeGroup,
                    photos: timePhotos.sorted { $0.creationDate > $1.creationDate },
                    coverPhoto: timePhotos.first?.thumbnail,
                    totalPhotos: timePhotos.count,
                    isParentNode: true,
                    parentCity: nil
                )
                locationGroups.append(locationGroup)
                // 注释掉刷屏的日志
                // print("🔍 [地点轴分组] 添加时间分组: \(timeGroup) [\(timePhotos.count)张]")
            }
        }
        
        print("🔍 [地点轴分组] 最终地点组数量: \(locationGroups.count)")
        
        // 智能排序：优先按时间，然后按照片数量
        locationGroups.sort { group1, group2 in
            let date1 = group1.photos.first?.creationDate ?? Date.distantPast
            let date2 = group2.photos.first?.creationDate ?? Date.distantPast
            
            if abs(date1.timeIntervalSince(date2)) < 3600 { // 1小时内
                // 时间接近时，按照片数量排序
                return group1.totalPhotos > group2.totalPhotos
            } else {
                // 时间差异大时，按时间排序
                return date1 > date2
            }
        }
        
        // 缓存结果
        cachedLocationGroups = locationGroups
        
        // 🚀 新增：更新数据指纹
        lastDataFingerprint = currentFingerprint
        print("🔍 [地点轴分组] 数据指纹已更新: \(lastDataFingerprint)")
        
        print("🔍 [地点轴分组] === 分组计算完成 ===")
        print("🔍 [地点轴分组] 返回分组数量: \(locationGroups.count)")
        print("🔍 [地点轴分组] 父节点数量: \(locationGroups.filter { $0.isParentNode }.count)")
        print("🔍 [地点轴分组] 子节点数量: \(locationGroups.filter { !$0.isParentNode }.count)")
        
        return locationGroups
    }
    
    private func groupPhotosByDetailedLocation(_ photos: [PhotoData]) -> [String: [PhotoData]] {
        var groups: [String: [PhotoData]] = [:]
        
        for photo in photos {
            let detailedLocation = getDetailedLocationName(for: photo)
            if groups[detailedLocation] == nil {
                groups[detailedLocation] = []
            }
            groups[detailedLocation]?.append(photo)
        }
        
        return groups
    }
    
    private func getDetailedLocationName(for photo: PhotoData) -> String {
        guard let location = photo.location else {
            return "未知地点"
        }
        
        // 优先使用详细地址
        if let address = location.address, !address.isEmpty {
            return address
        }
        
        // 如果有城市和地区信息
        if let city = location.city, let state = location.state, city != state {
            return "\(city), \(state)"
        }
        
        // 只有城市信息
        if let city = location.city {
            return city
        }
        
        // 只有地区信息
        if let state = location.state {
            return state
        }
        
        return "未知地点"
    }
    
    private func getDateRange(from photos: [PhotoData]) -> String {
        guard let firstDate = photos.map({ $0.creationDate }).min(),
              let lastDate = photos.map({ $0.creationDate }).max() else {
            return ""
        }
        
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy年MM月dd日"
        
        let startDate = formatter.string(from: firstDate)
        let endDate = formatter.string(from: lastDate)
        
        return startDate == endDate ? startDate : "\(startDate) - \(endDate)"
    }
    
    // MARK: - 按需加载原图
    
    func loadOriginalImage(for photoId: String) async -> UIImage? {
        guard let photo = photos.first(where: { $0.id == photoId }) else {
            return nil
        }
        
        return await getOriginalImage(for: photo.asset)
    }
    
    // MARK: - 功能检查（简化版）
    private func checkFunctionE() {
        let photosWithLocation = photos.filter { $0.location != nil }
        print("📸 功能检查: 总照片数 \(photos.count), 有地理信息 \(photosWithLocation.count)")
    }
    
    // MARK: - 性能监控（简化版）
    private func logPerformanceSummary() {
        print("📊 性能监控: 简化版，移除冗余计时器")
    }
    
    // 🚀 新增：缓存预热功能
    private func warmupAddressCache() async {
        print("🔥 开始地址缓存预热...")
        
        // 检查是否有足够的缓存数据
        let stats = getCacheStats()
        if stats.totalCache > 200 {
            print("🔥 缓存数据充足 (\(stats.totalCache) 条)，跳过预热")
            return
        }
        
        // 从照片数据中提取常用坐标进行预热
        let commonCoordinates = extractCommonCoordinates()
        if commonCoordinates.isEmpty {
            print("🔥 没有找到常用坐标，跳过预热")
            return
        }
        
        print("🔥 发现 \(commonCoordinates.count) 个常用坐标，开始预热...")
        
        // 并发预热常用坐标
        await withTaskGroup(of: Void.self) { group in
            for coordinate in commonCoordinates.prefix(20) { // 增加预热数量（适应5000张照片）
                group.addTask {
                    _ = await self.geocodeCoordinate(coordinate)
                }
            }
        }
        
        print("🔥 地址缓存预热完成")
    }
    
    // 🚀 新增：提取常用坐标
    private func extractCommonCoordinates() -> [CLLocationCoordinate2D] {
        var coordinateCounts: [CLLocationCoordinate2D: Int] = [:]
        
        for photo in photos {
            if let location = photo.location {
                let coordinate = location.coordinate
                coordinateCounts[coordinate, default: 0] += 1
            }
        }
        
        // 按出现频率排序，返回最常用的坐标
        return coordinateCounts.sorted { $0.value > $1.value }
            .prefix(20) // 取前20个最常用的坐标
            .map { $0.key }
    }
    
    // 🚀 新增：性能优化报告（简化版）
    private func generateOptimizationReport() {
        let stats = getCacheStats()
        let hitRate = stats.hits + stats.misses > 0 ? Double(stats.hits) / Double(stats.hits + stats.misses) * 100 : 0
        let timeHitRate = timeBasedCacheHitCount + timeBasedCacheMissCount > 0 ? Double(timeBasedCacheHitCount) / Double(timeBasedCacheHitCount + timeBasedCacheMissCount) * 100 : 0
        
        print("📈 性能报告: 缓存命中率 \(String(format: "%.1f", hitRate))%, 时间优化命中率 \(String(format: "%.1f", timeHitRate))%")
    }
    
    // 🚀 新增：清理过期缓存
    private func cleanupExpiredCache() {
        // 由于SerializableLocationInfo没有creationDate，暂时跳过过期清理
        // 可以通过其他方式实现缓存清理，比如基于缓存大小
        let maxCacheSize = 2000 // 最大缓存条目数（适应5000张照片）
        
        if addressCache.count > maxCacheSize {
            // 只保留前maxCacheSize个条目
            let itemsToKeep = addressCache.prefix(maxCacheSize)
            addressCache = Dictionary(uniqueKeysWithValues: itemsToKeep.map { ($0.key, $0.value) })
            saveAddressCache()
            print("🧹 缓存大小超过限制，已清理到 \(addressCache.count) 条")
        }
    }
    
    // 🚀 新增：设置地点分析通知监听
    private func setupLocationAnalysisNotification() {
        // 🚀 修复：先移除之前的监听器，避免重复注册
        NotificationCenter.default.removeObserver(self, name: NSNotification.Name("StartLocationAnalysis"), object: nil)
        
        // 🚀 新增：使用静态变量防止重复注册
        if Self.isObserverRegistered {
            return
        }
        
        NotificationCenter.default.addObserver(
            forName: NSNotification.Name("StartLocationAnalysis"),
            object: nil,
            queue: .main
        ) { [weak self] notification in
            guard let self = self else { return }
            
            if let userInfo = notification.userInfo,
               let group = userInfo["group"] as? LocationGroup {
                print("🔍 收到地点分析请求: \(group.city)")
                Task {
                    // 🚀 修改：手动刷新时强制重新解析未知地点
                    await self.analyzeUnknownLocations(for: group, forceReGeocode: true)
                }
            }
        }
        
        Self.isObserverRegistered = true
    }
    
    // 🚀 新增：分析未知地点
    private func analyzeUnknownLocations(for group: LocationGroup, forceReGeocode: Bool = false) async {
        print("🔍 === 开始分析未知地点 ===")
        print("🔍 目标组: \(group.city), 照片数量: \(group.totalPhotos)")
        // 🚀 修改：获取所有需要重新解析的照片（未知城市、未知地点、解析失败的照片）
        let unknownPhotos = group.photos.filter { photo in
            guard let location = photo.location else { return true }
            let isUnknownCity = location.city == "未知城市" || location.city == "未知" || location.city == nil
            let isUnknownCountry = location.country == "未知国家" || location.country == "未知" || location.country == nil
            let hasNoAddress = location.address == "未知地点" || location.address == "未知" || location.address == nil
            return isUnknownCity || isUnknownCountry || hasNoAddress
        }
        print("🔍 发现 \(unknownPhotos.count) 张未知地点的照片")
        if unknownPhotos.isEmpty {
            print("🔍 没有需要分析的未知地点照片")
            return
        }
        await MainActor.run {
            self.isGeocodingInProgress = true
            self.geocodingProgress = 0.0
            self.geocodingCurrentPhoto = 0
            self.geocodingTotalPhotos = unknownPhotos.count
            self.unknownPhotosCount = unknownPhotos.count  // 🚀 新增：初始化未知照片数量
        }
        let batchSize = 10
        var processedCount = 0
        for batch in stride(from: 0, to: unknownPhotos.count, by: batchSize) {
            let endIndex = min(batch + batchSize, unknownPhotos.count)
            let photoBatch = Array(unknownPhotos[batch..<endIndex])
            print("[PhotoService.geocodeUnknownPhotos] 🔍 处理批次 \(batch/batchSize + 1): \(photoBatch.count) 张照片")
            for photo in photoBatch {
                await self.geocodePhotoLocation(photo, forceReGeocode: forceReGeocode)
                processedCount += 1
                await MainActor.run {
                    self.geocodingProgress = Double(processedCount) / Double(unknownPhotos.count)
                    self.geocodingCurrentPhoto = processedCount
                    // 🚀 新增：实时更新未知照片数量，UI会自动刷新
                    self.unknownPhotosCount = unknownPhotos.count - processedCount
                }
                try? await Task.sleep(nanoseconds: 100_000_000)
            }
            try? await Task.sleep(nanoseconds: 500_000_000)
        }
        await MainActor.run {
            self.isGeocodingInProgress = false
            self.geocodingProgress = 1.0
        }
        print("[PhotoService.geocodeUnknownPhotos] 🔍 === 未知地点分析完成 ===")
        print("[PhotoService.geocodeUnknownPhotos] 🔍 处理了 \(processedCount) 张照片")
        generateOptimizationReport()
    }
    
    // 🚀 新增：地理编码单张照片（集成相邻照片时间维度优化）
    private func geocodePhotoLocation(_ photo: PhotoData, forceReGeocode: Bool = false) async {
        guard let location = photo.location else { return }
        let coordinate = location.coordinate
        let coordinateKey = coordinateKey(coordinate)
        let now = Date()
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
        let timestamp = formatter.string(from: now)
        
        if (geocodingCurrentPhoto + 1) % 10 == 0 {
            print("[PhotoService.geocodePhotoLocation] [\(timestamp)] 📸 正在处理第\(geocodingCurrentPhoto + 1)张照片...")
        }
        
        print("[PhotoService.geocodePhotoLocation] [\(timestamp)] 📸 照片ID: \(photo.id), 拍摄时间: \(photo.creationDate)")
        print("[PhotoService.geocodePhotoLocation] [\(timestamp)] 📍 GPS坐标: 纬度=\(coordinate.latitude), 经度=\(coordinate.longitude)")
        
        // 🚀 新增：第一步：检查已知解析地址
        if let matchingAddress = findMatchingKnownAddress(for: coordinate) {
            print("[PhotoService.geocodePhotoLocation] [\(timestamp)] ✅ 在已知地址中找到匹配: \(matchingAddress.address ?? "无地址")")
            let locationInfo = convertKnownAddressToLocationInfo(matchingAddress)
            
                         // 保存到地址缓存
             let serializableLocationInfo = SerializableLocationInfo(from: locationInfo)
             addressCache[coordinateKey] = serializableLocationInfo
             saveAddressCache()
            
            await updatePhotoLocation(photo, with: locationInfo)
            lastProcessedPhoto = photo
            return
        }
        
        print("[PhotoService.geocodePhotoLocation] [\(timestamp)] ❌ 未在已知地址中找到匹配，继续其他检查...")
        
        // 🚀 新增：手动刷新时，上一张为未知则不复用
        if forceReGeocode {
            if let lastPhoto = lastProcessedPhoto, let lastLocation = lastPhoto.location, lastLocation.isUnknown {
                // 不复用，强制API解析
            } else if let lastPhoto = lastProcessedPhoto, let lastLocation = lastPhoto.location {
                let timeDifference = abs(photo.creationDate.timeIntervalSince(lastPhoto.creationDate))
                if timeDifference <= timeSimilarityThreshold {
                    print("[PhotoService.geocodePhotoLocation] [\(timestamp)] ⏰ 时间优化: \(coordinateKey) -> 复用上一张照片地址")
                    await updatePhotoLocation(photo, with: lastLocation)
                    let serializableInfo = SerializableLocationInfo(from: lastLocation)
                    addressCache[coordinateKey] = serializableInfo
                    saveAddressCache()
                    timeBasedCacheHitCount += 1
                    lastProcessedPhoto = photo
                    return
                }
            }
        } else {
            if let lastPhoto = lastProcessedPhoto, let lastLocation = lastPhoto.location {
                let timeDifference = abs(photo.creationDate.timeIntervalSince(lastPhoto.creationDate))
                if timeDifference <= timeSimilarityThreshold {
                    print("[PhotoService.geocodePhotoLocation] [\(timestamp)] ⏰ 时间优化: \(coordinateKey) -> 复用上一张照片地址")
                    await updatePhotoLocation(photo, with: lastLocation)
                    let serializableInfo = SerializableLocationInfo(from: lastLocation)
                    addressCache[coordinateKey] = serializableInfo
                    saveAddressCache()
                    timeBasedCacheHitCount += 1
                    lastProcessedPhoto = photo
                    return
                }
            }
        }
        timeBasedCacheMissCount += 1
        
        if let cachedInfo = addressCache[coordinateKey] {
            cacheHitCount += 1
            let locationInfo = cachedInfo.toLocationInfo()
            await updatePhotoLocation(photo, with: locationInfo)
            lastProcessedPhoto = photo
            return
        }
        
        print("[PhotoService.geocodePhotoLocation] [\(timestamp)] 🔍 缓存未命中，开始API调用: \(coordinateKey)")
        cacheMissCount += 1
        
        let (locationInfo, _) = await withCheckedContinuation { continuation in
            geocodingQueue.async {
                self.geocodingSemaphore.wait()
                Task {
                    let result = await self.performGeocodingAPI(coordinate: coordinate, coordinateKey: coordinateKey)
                    self.geocodingSemaphore.signal()
                    continuation.resume(returning: result)
                }
            }
        }
        
        if let locationInfo = locationInfo {
            let serializableInfo = SerializableLocationInfo(from: locationInfo)
            addressCache[coordinateKey] = serializableInfo
            saveAddressCache()
            await updatePhotoLocation(photo, with: locationInfo)
            lastProcessedPhoto = photo
        }
    }
    
    // 🚀 新增：更新照片位置信息（优化版）
    private func updatePhotoLocation(_ photo: PhotoData, with locationInfo: LocationInfo) async {
        // 🚀 性能优化：批量更新，减少MainActor调用
        await MainActor.run {
            // 在photos数组中找到并更新对应的照片
            if let index = self.photos.firstIndex(where: { $0.id == photo.id }) {
                self.photos[index].location = locationInfo
                self.photos[index].hasGeocodingAttempted = true
                
                // 更新持久化数据（异步执行，不阻塞主线程）
                self.updatePhotoDataInMap(photo.id, self.photos[index])
            }
        }
        
        // 🚀 修复：立即保存到持久化存储，确保数据不丢失
        savePhotoDataMap()
        
        // 🚀 性能优化：移除频繁的缓存清除和通知发送
        // 这些操作在批量处理完成后统一执行
        // self.cachedLocationGroups = []
        // self.lastPhotoCount = 0
        // self.lastDataFingerprint = ""
        // NotificationCenter.default.post(name: NSNotification.Name("RefreshLocationAxis"), object: nil)
        // let locationGroupService = LocationGroupService()
        // locationGroupService.forceRefreshInternal()
    }
    
    // MARK: - 测试方法
    
    /// 测试AppleGeocodingService的方法
    func testAppleGeocodingService() async {
        print("[PhotoService.testAppleGeocodingService] 🧪 === 开始测试AppleGeocodingService ===")
        
        let testCoordinates = [
            ("北京天安门", CLLocationCoordinate2D(latitude: 39.9042, longitude: 116.4074)),
            ("上海外滩", CLLocationCoordinate2D(latitude: 31.2304, longitude: 121.4737)),
            ("广州塔", CLLocationCoordinate2D(latitude: 23.1066, longitude: 113.3213))
        ]
        
        for (name, coordinate) in testCoordinates {
            let startTime = Date()
            print("[PhotoService.testAppleGeocodingService] 🧪 测试坐标: \(name) - \(coordinate.latitude), \(coordinate.longitude)")
            
            if let result = await AppleGeocodingService.shared.fetchAddressInfoAsync(
                latitude: coordinate.latitude,
                longitude: coordinate.longitude
            ) {
                let endTime = Date()
                let duration = endTime.timeIntervalSince(startTime)
                print("[PhotoService.testAppleGeocodingService] ✅ AppleGeocodingService成功: \(name)")
                print("[PhotoService.testAppleGeocodingService] 📍 地址: \(result.displayName)")
                print("[PhotoService.testAppleGeocodingService] 🏙️ 城市: \(result.cityName)")
                print("[PhotoService.testAppleGeocodingService] 🌍 国家: \(result.countryName)")
                print("[PhotoService.testAppleGeocodingService] ⏱️ 耗时: \(String(format: "%.3f", duration))秒")
            } else {
                let endTime = Date()
                let duration = endTime.timeIntervalSince(startTime)
                print("[PhotoService.testAppleGeocodingService] ❌ AppleGeocodingService失败: \(name)")
                print("[PhotoService.testAppleGeocodingService] ⏱️ 耗时: \(String(format: "%.3f", duration))秒")
            }
            print("")
        }
        
        print("[PhotoService.testAppleGeocodingService] 🧪 === AppleGeocodingService测试完成 ===")
    }
    
    /// 使用当前配置测试地理编码
    func testGeocodingWithCurrentConfig(coordinate: CLLocationCoordinate2D) async -> LocationInfo? {
        print("🧪 === 使用当前配置测试地理编码 ===")
        print("📍 测试坐标: \(coordinate.latitude), \(coordinate.longitude)")
        
        let (result, usedService) = await performGeocodingAPI(coordinate: coordinate, coordinateKey: coordinateKey(coordinate))
        
        if let locationInfo = result, let usedService = usedService {
            print("✅ 地理编码成功 (\(usedService.displayName)): \(locationInfo.city ?? "未知") - \(locationInfo.address ?? "未知")")
        } else {
            print("❌ 地理编码失败")
        }
        
        print("🧪 === 当前配置测试完成 ===")
        return result
    }
    
    /// 检查并修复地理编码配置
    private func checkAndFixGeocodingConfig() {
        let config = GeocodingConfig.shared
        let validation = config.validateConfig()
        
        print("[PhotoService.checkAndFixGeocodingConfig] 🔍 检查地理编码配置...")
        
        if !validation {
            print("[PhotoService.checkAndFixGeocodingConfig] ⚠️ 地理编码配置无效")
            print("[PhotoService.checkAndFixGeocodingConfig] 🔧 正在修复配置...")
            
            // 强制重置配置
            config.resetConfig()
            
            // 再次验证
            let newValidation = config.validateConfig()
            if newValidation {
                print("[PhotoService.checkAndFixGeocodingConfig] ✅ 地理编码配置已修复")
            } else {
                print("[PhotoService.checkAndFixGeocodingConfig] ❌ 地理编码配置修复失败")
            }
        } else {
            print("[PhotoService.checkAndFixGeocodingConfig] ✅ 地理编码配置正常")
        }
    }
    
    // 🚀 新增：测试相邻照片时间维度优化功能
    func testAdjacentPhotoTimeOptimization() async {
        print("🧪 === 开始测试相邻照片时间维度优化功能 ===")
        
        // 重置最后处理的照片
        lastProcessedPhoto = nil
        timeBasedCacheHitCount = 0
        timeBasedCacheMissCount = 0
        
        // 创建测试照片数据
        let baseTime = Date()
        let testPhotos = [
            PhotoData(
                id: "test1",
                creationDate: baseTime,
                location: LocationInfo(
                    coordinate: CLLocationCoordinate2D(latitude: 39.9042, longitude: 116.4074),
                    country: "中国",
                    state: "北京",
                    city: "北京",
                    address: "天安门广场"
                ),
                thumbnail: nil,
                originalImage: nil,
                asset: PHAsset()
            ),
            PhotoData(
                id: "test2",
                creationDate: baseTime.addingTimeInterval(15), // 15秒后
                location: LocationInfo(
                    coordinate: CLLocationCoordinate2D(latitude: 39.9042, longitude: 116.4074),
                    country: nil,
                    state: nil,
                    city: nil,
                    address: nil
                ),
                thumbnail: nil,
                originalImage: nil,
                asset: PHAsset()
            ),
            PhotoData(
                id: "test3",
                creationDate: baseTime.addingTimeInterval(45), // 45秒后（超出30秒阈值）
                location: LocationInfo(
                    coordinate: CLLocationCoordinate2D(latitude: 39.9042, longitude: 116.4074),
                    country: nil,
                    state: nil,
                    city: nil,
                    address: nil
                ),
                thumbnail: nil,
                originalImage: nil,
                asset: PHAsset()
            )
        ]
        
        print("🧪 测试照片1（基准照片）: \(testPhotos[0].creationDate)")
        print("🧪 测试照片2（15秒后）: \(testPhotos[1].creationDate)")
        print("🧪 测试照片3（45秒后）: \(testPhotos[2].creationDate)")
        
        // 模拟地理编码处理流程
        print("🧪 开始模拟地理编码处理流程...")
        
        // 处理第一张照片（基准照片）
        print("🧪 处理照片1（基准照片）...")
        await geocodePhotoLocation(testPhotos[0])
        
        // 处理第二张照片（15秒后，应该复用地址）
        print("🧪 处理照片2（15秒后，应该复用地址）...")
        await geocodePhotoLocation(testPhotos[1])
        
        // 处理第三张照片（45秒后，超出阈值，不应该复用）
        print("🧪 处理照片3（45秒后，超出阈值，不应该复用）...")
        await geocodePhotoLocation(testPhotos[2])
        
        // 显示统计信息
        print("🧪 相邻照片时间维度优化统计:")
        print("🧪 命中次数: \(timeBasedCacheHitCount)")
        print("🧪 未命中次数: \(timeBasedCacheMissCount)")
        let hitRate = timeBasedCacheHitCount + timeBasedCacheMissCount > 0 ? Double(timeBasedCacheHitCount) / Double(timeBasedCacheHitCount + timeBasedCacheMissCount) * 100 : 0
        print("🧪 命中率: \(String(format: "%.1f", hitRate))%")
        
        print("🧪 === 相邻照片时间维度优化功能测试完成 ===")
    }
    
    // 🚀 新增：打印未能解析成功或解析结果是未知城市的照片地理信息（安全版）
    func printUnresolvedPhotosInfo() {
        print("🔍 === 开始分析未能解析成功或解析结果是未知城市的照片 ===")
        
        // 🚀 新增：photos数组非空判断
        guard !photos.isEmpty else {
            print("⚠️ [警告] photos数组为空，跳过分析")
            print("🔍 === 未能解析成功的照片分析完成（数组为空） ===")
            return
        }
        
        print("🔍 [验证] photos数组不为空，继续分析...")
        
        do {
            // 🚀 新增：详细的photos数组生命周期分析
            print("🔍 [生命周期分析] === photos数组状态检查 ===")
            
            // 安全地获取photos数组信息
            let photosCount = photos.count
            let photosIsEmpty = photos.isEmpty
            let photosCapacity = photos.capacity
            
            print("🔍 [生命周期分析] photos数组大小: \(photosCount)")
            print("🔍 [生命周期分析] photos数组是否为空: \(photosIsEmpty)")
            print("🔍 [生命周期分析] photos数组容量: \(photosCapacity)")
            
            // 检查photos数组的内存状态
            let memoryInfo = ProcessInfo.processInfo
            let physicalMemory = memoryInfo.physicalMemory
            let memoryInMB = physicalMemory / 1024 / 1024
            print("🔍 [生命周期分析] 系统物理内存: \(memoryInMB) MB")
            
            // 检查photos数组中的PhotoData对象状态
            var validPhotoDataCount = 0
            var invalidPhotoDataCount = 0
            var nilLocationCount = 0
            var emptyIdCount = 0
            
            // 安全地遍历photos数组
            for (index, photo) in photos.enumerated() {
                if index % 1000 == 0 {
                    print("🔍 [生命周期分析] 已检查 \(index) 张照片...")
                }
                
                // 安全地检查PhotoData对象的基本属性
                do {
                    let photoId = photo.id
                    if photoId.isEmpty {
                        emptyIdCount += 1
                        print("🔍 [生命周期分析] 照片 \(index) ID为空")
                        continue
                    }
                    
                    let photoLocation = photo.location
                    if photoLocation == nil {
                        nilLocationCount += 1
                    } else {
                        validPhotoDataCount += 1
                    }
                } catch {
                    invalidPhotoDataCount += 1
                    print("🔍 [生命周期分析] 照片 \(index) 访问异常: \(error)")
                }
            }
            
            print("🔍 [生命周期分析] 有效PhotoData: \(validPhotoDataCount)")
            print("🔍 [生命周期分析] 无效PhotoData: \(invalidPhotoDataCount)")
            print("🔍 [生命周期分析] 无位置信息: \(nilLocationCount)")
            print("🔍 [生命周期分析] 空ID照片: \(emptyIdCount)")
            
            // 检查photos数组的线程安全性
            print("🔍 [生命周期分析] 当前线程: \(Thread.current)")
            print("🔍 [生命周期分析] 是否在主线程: \(Thread.isMainThread)")
            
            // 基本统计
            let totalPhotos = photosCount
            let photosWithLocation = photos.filter { photo in
                do {
                    return photo.location != nil
                } catch {
                    return false
                }
            }.count
            let photosWithoutLocation = totalPhotos - photosWithLocation
            
            print("🔍 总照片数: \(totalPhotos)")
            print("🔍 有位置信息的照片: \(photosWithLocation)")
            print("🔍 无位置信息的照片: \(photosWithoutLocation)")
            
            // 简单统计未知地址的照片
            var unknownAddressCount = 0
            var unknownCityCount = 0
            var unknownCountryCount = 0
            var photosWithLocationButUnknown = 0
            
            for photo in photos {
                do {
                    guard let location = photo.location else {
                        // 没有位置信息的照片，算作未知地址
                        unknownAddressCount += 1
                        continue
                    }
                    
                    // 有位置信息但地址未知的照片
                    let hasAddress = location.address != nil && location.address != "未知" && location.address != "未知地点"
                    let hasCity = location.city != nil && location.city != "未知" && location.city != "未知城市"
                    let hasCountry = location.country != nil && location.country != "未知" && location.country != "未知国家"
                    
                    if !hasAddress {
                        unknownAddressCount += 1
                    }
                    
                    if !hasCity {
                        unknownCityCount += 1
                    }
                    
                    if !hasCountry {
                        unknownCountryCount += 1
                    }
                    
                    // 统计有位置信息但地址未知的照片
                    if !hasAddress || !hasCity || !hasCountry {
                        photosWithLocationButUnknown += 1
                    }
                } catch {
                    print("🔍 [错误] 处理照片时出现异常: \(error)")
                    unknownAddressCount += 1
                }
            }
            
            print("🔍 === 详细统计信息 ===")
            print("🔍 总照片数: \(totalPhotos)")
            print("🔍 有位置信息的照片: \(photosWithLocation)")
            print("🔍 无位置信息的照片: \(photosWithoutLocation)")
            print("🔍 有位置信息但地址未知的照片: \(photosWithLocationButUnknown)")
            print("🔍 未知地址的照片: \(unknownAddressCount)")
            print("🔍 未知城市的照片: \(unknownCityCount)")
            print("🔍 未知国家的照片: \(unknownCountryCount)")
            
            // 验证数据一致性
            let expectedUnknownAddress = photosWithoutLocation + photosWithLocationButUnknown
            print("🔍 === 数据一致性检查 ===")
            print("🔍 预期未知地址照片数: \(expectedUnknownAddress) (无位置信息 \(photosWithoutLocation) + 有位置但未知 \(photosWithLocationButUnknown))")
            print("🔍 实际未知地址照片数: \(unknownAddressCount)")
            print("🔍 数据是否一致: \(expectedUnknownAddress == unknownAddressCount ? "✅ 是" : "❌ 否")")
            
            let successRate = totalPhotos > 0 ? Double(totalPhotos - unknownAddressCount) / Double(totalPhotos) * 100 : 0
            print("🔍 解析成功率: \(String(format: "%.1f", successRate))%")
            
        } catch {
            print("❌ [错误] printUnresolvedPhotosInfo 执行失败: \(error.localizedDescription)")
            print("❌ [错误] 错误详情: \(error)")
        }
        
        print("🔍 === 未能解析成功的照片分析完成 ===")
    }
    
    // 🚀 新增：调试照片加载状态
    func debugPhotoLoadingStatus() {
        print("🔍 === 照片加载状态调试 ===")
        print("🔍 本机总照片数: \(totalPhotoCount)")
        print("🔍 已加载照片数: \(photos.count)")
        print("🔍 有地理信息的照片: \(photos.filter { $0.location != nil }.count)")
        print("🔍 无地理信息的照片: \(photos.filter { $0.location == nil }.count)")
        
        // 检查分组状态（已禁用旧分组方法，使用新的LocationGroupService）
        print("🔍 分组状态: 已迁移到新的LocationGroupService")
        print("🔍 请使用LocationGroupService.getLocationGroups()方法")
        
        // 检查持久化数据
        print("🔍 持久化数据映射大小: \(photoDataMap.count)")
        print("🔍 已处理照片ID数量: \(processedPhotoIds.count)")
        
        // 检查地址缓存
        let stats = getCacheStats()
        print("🔍 地址缓存统计: 命中 \(stats.hits) 次，未命中 \(stats.misses) 次，API调用 \(stats.apiCalls) 次")
        
        print("🔍 === 调试完成 ===")
    }
    
    // MARK: - 照片解析优化方法
    
    /// 按钮A：打印一张未知地址的照片信息
    func printUnknownPhotoInfo() {
        print("🔍 === 按钮A：打印未知地址照片信息 ===")
        
        // 只统计有地理信息的照片中的未知地址照片
        let photosWithLocation = photos.filter { $0.location != nil }
        let unknownPhotos = photosWithLocation.filter { photo in
            guard let location = photo.location else { return false }
            let hasAddress = location.address != nil && location.address != "未知" && location.address != "未知地点"
            let hasCity = location.city != nil && location.city != "未知" && location.city != "未知城市"
            let hasCountry = location.country != nil && location.country != "未知" && location.country != "未知国家"
            return !hasAddress || !hasCity || !hasCountry
        }
        
        if let firstUnknownPhoto = unknownPhotos.first {
            print("🔍 找到未知地址照片:")
            print("  - 照片ID: \(firstUnknownPhoto.id)")
            print("  - 拍摄时间: \(firstUnknownPhoto.creationDate)")
            
            // 确保照片有地理坐标信息
            if let location = firstUnknownPhoto.location {
                print("  - 坐标: \(location.coordinate.latitude), \(location.coordinate.longitude)")
                print("  - 地址: \(location.address ?? "未知")")
                print("  - 城市: \(location.city ?? "未知")")
                print("  - 国家: \(location.country ?? "未知")")
            } else {
                print("  - 无地理坐标信息")
            }
        } else {
            print("🔍 没有找到未知地址的照片")
        }
        
        print("🔍 有地理信息的照片总数: \(photosWithLocation.count)")
        print("🔍 其中未知地址的照片: \(unknownPhotos.count)")
        print("🔍 === 按钮A完成 ===")
    }
    
    /// 按钮B：按照优先级，进行解析，打印日志
    func parseSinglePhotoWithPriority() async {
        print("🔍 === 按钮B：按优先级解析单张照片 ===")
        
        // 只从有地理信息的照片中找到第一张未知地址的照片
        let photosWithLocation = photos.filter { $0.location != nil }
        let unknownPhotos = photosWithLocation.filter { photo in
            guard let location = photo.location else { return false }
            let hasAddress = location.address != nil && location.address != "未知" && location.address != "未知地点"
            let hasCity = location.city != nil && location.city != "未知" && location.city != "未知城市"
            let hasCountry = location.country != nil && location.country != "未知" && location.country != "未知国家"
            return !hasAddress || !hasCity || !hasCountry
        }
        
        guard let targetPhoto = unknownPhotos.first else {
            print("🔍 没有找到需要解析的照片（有地理信息但地址未知的照片）")
            return
        }
        
        print("🔍 开始解析照片: \(targetPhoto.id)")
        print("🔍 拍摄时间: \(targetPhoto.creationDate)")
        
        if let location = targetPhoto.location {
            print("🔍 坐标: \(location.coordinate.latitude), \(location.coordinate.longitude)")
            
            // 按优先级尝试解析：缓存地址 -> 苹果本地 -> 高德 -> 腾讯 -> 谷歌 -> openStreet
            let coordinate = location.coordinate
            let coordinateKey = coordinateKey(coordinate)
            
            print("🔍 优先级解析顺序：已知地址 -> 缓存地址 -> 苹果本地 -> 高德 -> 腾讯 -> 谷歌 -> openStreet")
            
            // 1. 检查已知解析地址
            if let matchingAddress = findMatchingKnownAddress(for: coordinate) {
                print("🔍 ✅ 在已知地址中找到匹配: \(matchingAddress.address ?? "无地址")")
                let locationInfo = convertKnownAddressToLocationInfo(matchingAddress)
                
                // 保存到地址缓存
                let serializableLocationInfo = SerializableLocationInfo(from: locationInfo)
                addressCache[coordinateKey] = serializableLocationInfo
                saveAddressCache()
                
                await updatePhotoLocation(targetPhoto, with: locationInfo)
                print("🔍 解析完成，使用已知地址数据")
                print("🔍 === 按钮B完成 ===")
                return
            }
            
            // 2. 检查缓存
            if let cachedInfo = addressCache[coordinateKey] {
                print("🔍 ✅ 缓存命中: \(coordinateKey)")
                let locationInfo = cachedInfo.toLocationInfo()
                await updatePhotoLocation(targetPhoto, with: locationInfo)
                print("🔍 解析完成，使用缓存数据")
                return
            }
            
            // 2. 尝试苹果本地地理编码
            print("🔍 🍎 尝试苹果本地地理编码...")
            if let appleResult = await tryAppleGeocoding(coordinate: coordinate, coordinateKey: coordinateKey) {
                await updatePhotoLocation(targetPhoto, with: appleResult)
                print("🔍 ✅ 苹果本地解析成功")
                print("🔍 === 按钮B完成 ===")
                return
            }
            
            // 3. 尝试高德地图
            print("🔍 🗺️ 尝试高德地图API...")
            if let amapResult = await tryAMapGeocoding(coordinate: coordinate, coordinateKey: coordinateKey) {
                await updatePhotoLocation(targetPhoto, with: amapResult)
                print("🔍 ✅ 高德地图解析成功")
                print("🔍 === 按钮B完成 ===")
                return
            }
            
            // 4. 尝试腾讯地图
            print("🔍 🗺️ 尝试腾讯地图API...")
            if let tencentResult = await tryTencentGeocoding(coordinate: coordinate, coordinateKey: coordinateKey) {
                await updatePhotoLocation(targetPhoto, with: tencentResult)
                print("🔍 ✅ 腾讯地图解析成功")
                print("🔍 === 按钮B完成 ===")
                return
            }
            
            // 5. 尝试谷歌地图
            print("🔍 🗺️ 尝试谷歌地图API...")
            if let googleResult = await tryGoogleGeocoding(coordinate: coordinate, coordinateKey: coordinateKey) {
                await updatePhotoLocation(targetPhoto, with: googleResult)
                print("🔍 ✅ 谷歌地图解析成功")
                print("🔍 === 按钮B完成 ===")
                return
            }
            
            // 6. 尝试OpenStreetMap
            print("🔍 🌍 尝试OpenStreetMap...")
            if let osmResult = await tryOpenStreetMapGeocoding(coordinate: coordinate, coordinateKey: coordinateKey) {
                await updatePhotoLocation(targetPhoto, with: osmResult)
                print("🔍 ✅ OpenStreetMap解析成功")
                print("🔍 === 按钮B完成 ===")
                return
            }
            
            print("🔍 ❌ 所有服务都解析失败")
        } else {
            print("🔍 照片没有地理坐标信息")
        }
        
        print("🔍 === 按钮B完成 ===")
    }
    
    /// 按钮C：解析单张照片，并自动保存到缓存
    func parseAndSaveSinglePhoto() async {
        print("🔍 === 按钮C：解析单张照片并保存到缓存 ===")
        
        // 只从有地理信息的照片中找到第一张未知地址的照片
        let photosWithLocation = photos.filter { $0.location != nil }
        let unknownPhotos = photosWithLocation.filter { photo in
            guard let location = photo.location else { return false }
            let hasAddress = location.address != nil && location.address != "未知" && location.address != "未知地点"
            let hasCity = location.city != nil && location.city != "未知" && location.city != "未知城市"
            let hasCountry = location.country != nil && location.country != "未知" && location.country != "未知国家"
            return !hasAddress || !hasCity || !hasCountry
        }
        
        guard let targetPhoto = unknownPhotos.first else {
            print("🔍 没有找到需要解析的照片（有地理信息但地址未知的照片）")
            return
        }
        
        print("🔍 开始解析并保存照片: \(targetPhoto.id)")
        
        // 调用按钮B的解析逻辑
        await parseSinglePhotoWithPriority()
        
        // 保存到持久化数据
        if let updatedPhoto = photos.first(where: { $0.id == targetPhoto.id }) {
            updatePhotoDataInMap(targetPhoto.id, updatedPhoto)
            savePhotoDataMap()
            print("🔍 ✅ 照片数据已保存到持久化存储")
            
            // 🚀 新增：保存地点轴分组（已迁移到新的LocationGroupService）
            print("🔍 ✅ 地点轴分组已迁移到新的LocationGroupService")
        }
        
        print("🔍 === 按钮C完成 ===")
    }
    
    /// 按钮D：将缓存的数据落地的持久化数组，如果有查重机制要强制覆盖
    func persistCacheData() {
        print("🔍 === 按钮D：将缓存数据落地持久化 ===")
        
        let startTime = Date()
        print("🔍 开始时间: \(startTime)")
        
        // 统计缓存数据
        let cacheStats = getCacheStats()
        print("🔍 缓存统计: 命中 \(cacheStats.hits) 次，未命中 \(cacheStats.misses) 次，API调用 \(cacheStats.apiCalls) 次")
        print("🔍 地址缓存大小: \(addressCache.count) 条")
        
        // 强制保存地址缓存
        saveAddressCache()
        print("🔍 ✅ 地址缓存已保存")
        
        // 强制保存照片数据映射
        savePhotoDataMap()
        print("🔍 ✅ 照片数据映射已保存")
        
        // 保存已处理照片ID
        saveProcessedPhotoIds()
        print("🔍 ✅ 已处理照片ID已保存")
        
        // 🚀 新增：保存地点轴分组（已迁移到新的LocationGroupService）
        print("🔍 ✅ 地点轴分组已迁移到新的LocationGroupService")
        
        let endTime = Date()
        let duration = endTime.timeIntervalSince(startTime)
        print("🔍 完成时间: \(endTime)")
        print("🔍 耗时: \(String(format: "%.2f", duration)) 秒")
        
        print("🔍 === 按钮D完成 ===")
    }
    
    /// 按钮E：刷新地点轴的分组UI，未知照片应该数量-1，对应城市和地区分组的照片应该+1
    func refreshLocationAxisUI() {
        print("🔍 === 按钮E：刷新地点轴分组UI ===")
        
        // 🚀 修复：强制清除缓存和数据指纹，确保重新计算
        cachedLocationGroups = []
        lastPhotoCount = 0
        lastDataFingerprint = "" // 🚀 新增：清除数据指纹，强制重新计算
        print("🔍 已清除地点轴缓存和数据指纹，强制重新计算")
        
        // 只统计有地理信息的照片
        let photosWithLocation = photos.filter { $0.location != nil }
        print("🔍 有地理信息的照片总数: \(photosWithLocation.count)")
        
        // 重新计算分组（已迁移到新的LocationGroupService）
        print("🔍 分组计算已迁移到新的LocationGroupService")
        let groups: [LocationGroup] = [] // 临时空数组，实际使用LocationGroupService
        
        // 🚀 修复：正确统计分组信息，避免重复计算
        var knownLocationPhotos = 0
        var unknownLocationPhotos = 0
        var timeGroupPhotos = 0
        
        for group in groups {
            if group.isParentNode {
                // 父节点统计
                if group.city == "未知城市" || group.city == "未知" {
                    // 这是时间分组（无地理信息的照片）
                    timeGroupPhotos += group.totalPhotos
                } else {
                    // 这是已知地点的父节点
                    knownLocationPhotos += group.totalPhotos
                }
            } else {
                // 子节点统计（已知地点的详细分组）
                knownLocationPhotos += group.totalPhotos
            }
            
            print("🔍 分组: \(group.city) - \(group.totalPhotos) 张照片")
        }
        
        // 统计未知地址的照片（有地理信息但地址未知）
        let unknownAddressPhotos = photosWithLocation.filter { photo in
            guard let location = photo.location else { return false }
            let hasAddress = location.address != nil && location.address != "未知" && location.address != "未知地点"
            let hasCity = location.city != nil && location.city != "未知" && location.city != "未知城市"
            let hasCountry = location.country != nil && location.country != "未知" && location.country != "未知国家"
            return !hasAddress || !hasCity || !hasCountry
        }.count
        
        print("🔍 分组统计:")
        print("  - 总分组数: \(groups.count)")
        print("  - 已知地点照片: \(knownLocationPhotos) 张")
        print("  - 时间分组照片: \(timeGroupPhotos) 张")
        print("  - 有地理信息但地址未知: \(unknownAddressPhotos) 张")
        print("  - 有地理信息照片总数: \(photosWithLocation.count)")
        
        // 验证数据一致性
        let totalPhotosInGroups = knownLocationPhotos + timeGroupPhotos
        let actualTotal = photos.count
        print("🔍 数据一致性检查:")
        print("  - 分组照片总数: \(totalPhotosInGroups)")
        print("  - 实际照片总数: \(actualTotal)")
        print("  - 一致性: \(totalPhotosInGroups == actualTotal ? "✅" : "❌")")
        
        // 🚀 修复：强制更新UI状态
        DispatchQueue.main.async {
            // 触发UI刷新
            self.objectWillChange.send()
            
            // 强制刷新地点轴视图
            NotificationCenter.default.post(name: NSNotification.Name("RefreshLocationAxis"), object: nil)
        }
        
        print("🔍 === 按钮E完成 ===")
    }
    
    // MARK: - 强制刷新分组功能
    /// 强制刷新地点分组数据，清除缓存并重新计算，保存并通知UI刷新
    func forceRefreshLocationGroups() {
        print("🔄 [强制刷新] 开始强制刷新地点分组数据")
        cachedLocationGroups = []
        lastPhotoCount = 0
        lastDataFingerprint = ""
        // 分组计算已迁移到新的LocationGroupService
        print("🔄 [强制刷新] 分组计算已迁移到新的LocationGroupService")
        NotificationCenter.default.post(name: NSNotification.Name("RefreshLocationAxis"), object: nil)
        print("🔄 [强制刷新] 地点分组数据刷新完成")
    }
    
    /// 清空所有地点分组缓存，强制UI重新加载
    func clearAllLocationGroups() {
        print("🗑️ [清空UI节点] 开始清空所有分组缓存")
        cachedLocationGroups = []
        lastPhotoCount = 0
        lastDataFingerprint = ""
        NotificationCenter.default.post(name: NSNotification.Name("RefreshLocationAxis"), object: nil)
        print("🗑️ [清空UI节点] 所有分组缓存已清空，UI将重新加载")
    }
    
    // MARK: - 已知解析地址管理
    
    private let knownAddressesKey = "KnownAddresses"
    private var knownAddresses: [KnownAddress] = []
    
    /// 已知解析地址结构
    struct KnownAddress: Codable {
        let latitude: Double
        let longitude: Double
        let country: String?
        let state: String?
        let city: String?
        let address: String?
        let timestamp: Date
        
        var coordinate: CLLocationCoordinate2D {
            return CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
        }
        
        init(coordinate: CLLocationCoordinate2D, locationInfo: LocationInfo) {
            self.latitude = coordinate.latitude
            self.longitude = coordinate.longitude
            self.country = locationInfo.country
            self.state = locationInfo.state
            self.city = locationInfo.city
            self.address = locationInfo.address
            self.timestamp = Date()
        }
    }
    
    /// 加载已知解析地址
    private func loadKnownAddresses() {
        if let data = UserDefaults.standard.data(forKey: knownAddressesKey),
           let addresses = try? JSONDecoder().decode([KnownAddress].self, from: data) {
            knownAddresses = addresses
            print("[PhotoService.loadKnownAddresses] 📂 已加载 \(addresses.count) 个已知解析地址")
        } else {
            knownAddresses = []
            print("[PhotoService.loadKnownAddresses] 📂 无已知解析地址，初始化为空数组")
        }
    }
    
    /// 保存已知解析地址
    private func saveKnownAddresses() {
        if let data = try? JSONEncoder().encode(knownAddresses) {
            UserDefaults.standard.set(data, forKey: knownAddressesKey)
            print("[PhotoService.saveKnownAddresses] 💾 已保存 \(knownAddresses.count) 个已知解析地址")
        } else {
            print("[PhotoService.saveKnownAddresses] ❌ 保存已知解析地址失败")
        }
    }
    
    /// 添加新的已知解析地址
    private func addKnownAddress(coordinate: CLLocationCoordinate2D, locationInfo: LocationInfo) {
        let newAddress = KnownAddress(coordinate: coordinate, locationInfo: locationInfo)
        
        // 检查是否已存在相同坐标的地址
        if let existingIndex = knownAddresses.firstIndex(where: { address in
            let distance = calculateDistance(from: coordinate, to: address.coordinate)
            return distance < 10 // 10米内视为相同位置
        }) {
            // 更新现有地址
            knownAddresses[existingIndex] = newAddress
            print("[PhotoService.addKnownAddress] 🔄 更新已知地址: \(coordinate.latitude), \(coordinate.longitude)")
        } else {
            // 添加新地址
            knownAddresses.append(newAddress)
            print("[PhotoService.addKnownAddress] ➕ 添加新已知地址: \(coordinate.latitude), \(coordinate.longitude)")
        }
        
        saveKnownAddresses()
    }
    
    /// 计算两个坐标之间的距离（米）
    private func calculateDistance(from coord1: CLLocationCoordinate2D, to coord2: CLLocationCoordinate2D) -> CLLocationDistance {
        let location1 = CLLocation(latitude: coord1.latitude, longitude: coord1.longitude)
        let location2 = CLLocation(latitude: coord2.latitude, longitude: coord2.longitude)
        return location1.distance(from: location2)
    }
    
    /// 在已知地址中查找匹配的地址
    private func findMatchingKnownAddress(for coordinate: CLLocationCoordinate2D) -> KnownAddress? {
        print("[PhotoService.findMatchingKnownAddress] 🔍 开始查找匹配的已知地址...")
        print("[PhotoService.findMatchingKnownAddress] 📍 目标坐标: \(coordinate.latitude), \(coordinate.longitude)")
        print("[PhotoService.findMatchingKnownAddress] 📊 已知地址总数: \(knownAddresses.count)")
        
        for (index, knownAddress) in knownAddresses.enumerated() {
            let distance = calculateDistance(from: coordinate, to: knownAddress.coordinate)
            print("[PhotoService.findMatchingKnownAddress] 🔍 检查地址 \(index + 1):")
            print("   - 坐标: \(knownAddress.coordinate.latitude), \(knownAddress.coordinate.longitude)")
            print("   - 距离: \(String(format: "%.2f", distance))米")
            print("   - 地址: \(knownAddress.address ?? "无")")
            
            if distance <= 500 { // 500米内视为匹配
                print("[PhotoService.findMatchingKnownAddress] ✅ 找到匹配地址 (距离: \(String(format: "%.2f", distance))米)")
                return knownAddress
            }
        }
        
        print("[PhotoService.findMatchingKnownAddress] ❌ 未找到匹配的已知地址")
        return nil
    }
    
    /// 将KnownAddress转换为LocationInfo
    private func convertKnownAddressToLocationInfo(_ knownAddress: KnownAddress) -> LocationInfo {
        return LocationInfo(
            coordinate: knownAddress.coordinate,
            country: knownAddress.country,
            state: knownAddress.state,
            city: knownAddress.city,
            address: knownAddress.address
        )
    }
    
    /// 打印当前已知解析地址数组内容
    func printKnownAddresses() {
        print("🔍 === 打印当前已知解析地址数组内容 ===")
        print("📊 已知地址总数: \(knownAddresses.count)")
        
        if knownAddresses.isEmpty {
            print("📭 已知地址数组为空")
        } else {
            for (index, address) in knownAddresses.enumerated() {
                print("🔍 地址 \(index + 1):")
                print("   - 坐标: \(address.coordinate.latitude), \(address.coordinate.longitude)")
                print("   - 国家: \(address.country ?? "nil")")
                print("   - 州/省: \(address.state ?? "nil")")
                print("   - 城市: \(address.city ?? "nil")")
                print("   - 地址: \(address.address ?? "nil")")
                print("   - 时间戳: \(address.timestamp)")
                print("")
            }
        }
        
        print("🔍 === 已知解析地址数组内容打印完成 ===")
    }
    
    // MARK: - 权限管理
    
    /// 批量解析未知地址照片
    func batchParseUnknownPhotos(count: Int) async {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
        let startTime = Date()
        let startTimestamp = formatter.string(from: startTime)
        print("🚀 [开始] 批量解析 \(count) 张照片，时间: \(startTimestamp)")
        
        // 🎯 修复：找到所有需要解析的照片（与LocationGroupService保持一致）
        let photosWithLocation = photos.filter { $0.location != nil }
        let unknownPhotos = photosWithLocation.filter { photo in
            guard let location = photo.location else { return false }
            // 位置信息不完整（未知国家/城市）
            let hasIncompleteCountry = location.country == nil || location.country == "未知国家" || location.country == "未知"
            let hasIncompleteCity = location.city == nil || location.city == "未知城市" || location.city == "未知"
            
            return hasIncompleteCountry || hasIncompleteCity
        }
        
        print("🚀 找到 \(unknownPhotos.count) 张未知地址照片")
        
        if unknownPhotos.isEmpty {
            print("🚀 没有找到需要解析的照片")
            return
        }
        
        // 限制处理数量
        let photosToProcess = Array(unknownPhotos.prefix(count))
        print("🚀 将处理前 \(photosToProcess.count) 张照片")
        
        // 设置进度跟踪
        await MainActor.run {
            self.isGeocodingInProgress = true
            self.geocodingProgress = 0.0
            self.geocodingCurrentPhoto = 0
            self.geocodingTotalPhotos = photosToProcess.count
        }
        
        var successCount = 0
        var failureCount = 0
        var knownAddressHitCount = 0
        var cacheHitCount = 0
        var apiCallCount = 0
        
        // 🚀 新增：API解析统计
        var appleSuccessCount = 0
        var googleSuccessCount = 0
        var amapSuccessCount = 0
        var tencentSuccessCount = 0
        var osmSuccessCount = 0
        var apiFailureCount = 0
        
        for (index, photo) in photosToProcess.enumerated() {
            let shouldLog = index % 10 == 0 || index == photosToProcess.count - 1
            if shouldLog {
                let now = Date()
                let timestamp = DateFormatter.localizedString(from: now, dateStyle: .none, timeStyle: .medium)
                print("🚀 [\(timestamp)] 处理第 \(index + 1)/\(photosToProcess.count) 张照片")
            }
            
            guard let location = photo.location else {
                if shouldLog {
                    print("🚀 照片没有地理坐标信息，跳过")
                }
                failureCount += 1
                continue
            }
            
            let coordinate = location.coordinate
            let coordinateKey = coordinateKey(coordinate)
            
            // 1. 检查已知解析地址
            if let matchingAddress = findMatchingKnownAddress(for: coordinate) {
                if shouldLog {
                    print("🚀 ✅ 已知地址命中: \(matchingAddress.address ?? "无地址")")
                }
                let locationInfo = convertKnownAddressToLocationInfo(matchingAddress)
                
                // 保存到地址缓存
                let serializableLocationInfo = SerializableLocationInfo(from: locationInfo)
                addressCache[coordinateKey] = serializableLocationInfo
                saveAddressCache()
                
                await updatePhotoLocation(photo, with: locationInfo)
                knownAddressHitCount += 1
                successCount += 1
                
                await MainActor.run {
                    self.geocodingProgress = Double(index + 1) / Double(photosToProcess.count)
                    self.geocodingCurrentPhoto = index + 1
                }
                
                // 添加延迟避免过快处理
                try? await Task.sleep(nanoseconds: 100_000_000) // 0.1秒
                continue
            }
            
            // 2. 检查缓存
            if let cachedInfo = addressCache[coordinateKey] {
                if shouldLog {
                    print("🚀 ✅ 缓存命中")
                }
                let locationInfo = cachedInfo.toLocationInfo()
                await updatePhotoLocation(photo, with: locationInfo)
                cacheHitCount += 1
                successCount += 1
                
                await MainActor.run {
                    self.geocodingProgress = Double(index + 1) / Double(photosToProcess.count)
                    self.geocodingCurrentPhoto = index + 1
                }
                
                try? await Task.sleep(nanoseconds: 100_000_000) // 0.1秒
                continue
            }
            
            // 3. 尝试API解析
            if shouldLog {
                print("🚀 🔍 开始API解析...")
            }
            apiCallCount += 1
            
            let (locationInfo, usedService) = await withCheckedContinuation { continuation in
                geocodingQueue.async {
                    self.geocodingSemaphore.wait()
                    Task {
                        let result = await self.performGeocodingAPI(coordinate: coordinate, coordinateKey: coordinateKey)
                        self.geocodingSemaphore.signal()
                        continuation.resume(returning: result)
                    }
                }
            }
            
            if let locationInfo = locationInfo, let usedService = usedService {
                if shouldLog {
                    print("🚀 ✅ API解析成功 (\(usedService.displayName)): \(locationInfo.city ?? "未知")")
                }
                successCount += 1
                
                // 🚀 新增：统计每种API的成功次数
                switch usedService {
                case .apple:
                    appleSuccessCount += 1
                case .google:
                    googleSuccessCount += 1
                case .amap:
                    amapSuccessCount += 1
                case .tencent:
                    tencentSuccessCount += 1
                case .openStreetMap:
                    osmSuccessCount += 1
                }
                
                // 🚀 修复：API解析成功时立即更新进度条
                await MainActor.run {
                    self.geocodingProgress = Double(index + 1) / Double(photosToProcess.count)
                    self.geocodingCurrentPhoto = index + 1
                }
            } else {
                if shouldLog {
                    print("🚀 ❌ API解析失败")
                }
                failureCount += 1
                apiFailureCount += 1
                
                // 🚀 修复：API解析失败时也更新进度条
                await MainActor.run {
                    self.geocodingProgress = Double(index + 1) / Double(photosToProcess.count)
                    self.geocodingCurrentPhoto = index + 1
                }
            }
            
            // 添加延迟避免过快请求
            try? await Task.sleep(nanoseconds: 500_000_000) // 0.5秒
        }
        
        let endTime = Date()
        let endTimestamp = formatter.string(from: endTime)
        let duration = endTime.timeIntervalSince(startTime)
        print("🚀 [结束] 批量解析 \(count) 张照片，时间: \(endTimestamp)")
        print("🚀 总耗时: \(String(format: "%.2f", duration)) 秒")
        
        await MainActor.run {
            self.isGeocodingInProgress = false
            self.geocodingProgress = 1.0
        }
        
        // 保存所有数据
        saveAddressCache()
        savePhotoDataMap()
        
        print("🚀 === 批量解析完成 ===")
        print("🚀 总耗时: \(String(format: "%.2f", duration)) 秒")
        print("🚀 处理照片数: \(photosToProcess.count)")
        print("🚀 成功解析: \(successCount) 张")
        print("🚀 解析失败: \(failureCount) 张")
        print("🚀 已知地址命中: \(knownAddressHitCount) 次")
        print("🚀 缓存命中: \(cacheHitCount) 次")
        print("🚀 API调用: \(apiCallCount) 次")
        print("🚀 API解析分布:")
        print("   - Apple: \(appleSuccessCount) 次")
        print("   - Google: \(googleSuccessCount) 次")
        print("   - 高德: \(amapSuccessCount) 次")
        print("   - 腾讯: \(tencentSuccessCount) 次")
        print("   - OpenStreetMap: \(osmSuccessCount) 次")
        print("   - API失败: \(apiFailureCount) 次")
        
        // 发送刷新通知
        NotificationCenter.default.post(name: NSNotification.Name("RefreshLocationAxis"), object: nil)
        print("🚀 已发送刷新通知")
    }
    
    /// 测试腾讯和高德API失败原因
    func testTencentAMapAPIFailures() async {
        print("🧪 === 开始测试腾讯和高德API失败原因 ===")
        
        // 准备10个测试坐标（来自不同地区）
        let testCoordinates = [
            ("北京天安门", CLLocationCoordinate2D(latitude: 39.9042, longitude: 116.4074)),
            ("上海外滩", CLLocationCoordinate2D(latitude: 31.2304, longitude: 121.4737)),
            ("广州塔", CLLocationCoordinate2D(latitude: 23.1066, longitude: 113.3213)),
            ("深圳世界之窗", CLLocationCoordinate2D(latitude: 22.5405, longitude: 113.9344)),
            ("杭州西湖", CLLocationCoordinate2D(latitude: 30.2741, longitude: 120.1551)),
            ("南京夫子庙", CLLocationCoordinate2D(latitude: 32.0603, longitude: 118.7969)),
            ("成都宽窄巷子", CLLocationCoordinate2D(latitude: 30.6586, longitude: 104.0657)),
            ("西安兵马俑", CLLocationCoordinate2D(latitude: 34.3844, longitude: 109.2787)),
            ("武汉黄鹤楼", CLLocationCoordinate2D(latitude: 30.5494, longitude: 114.3054)),
            ("重庆洪崖洞", CLLocationCoordinate2D(latitude: 29.5647, longitude: 106.5501))
        ]
        
        print("🧪 测试坐标列表:")
        for (index, (name, coordinate)) in testCoordinates.enumerated() {
            print("🧪 \(index + 1). \(name): \(coordinate.latitude), \(coordinate.longitude)")
        }
        print("")
        
        var amapSuccessCount = 0
        var amapFailureCount = 0
        var tencentSuccessCount = 0
        var tencentFailureCount = 0
        
        for (index, (name, coordinate)) in testCoordinates.enumerated() {
            print("🧪 === 测试 \(index + 1)/10: \(name) ===")
            print("🧪 坐标: \(coordinate.latitude), \(coordinate.longitude)")
            
            // 测试高德API
            print("🧪 🗺️ 测试高德API...")
            let amapStartTime = Date()
            if let amapResult = await tryAMapGeocoding(coordinate: coordinate, coordinateKey: coordinateKey(coordinate)) {
                let amapDuration = Date().timeIntervalSince(amapStartTime)
                print("🧪 ✅ 高德API成功: \(amapResult.city ?? "未知") - \(amapResult.address ?? "未知") (耗时: \(String(format: "%.2f", amapDuration))秒)")
                amapSuccessCount += 1
            } else {
                let amapDuration = Date().timeIntervalSince(amapStartTime)
                print("🧪 ❌ 高德API失败 (耗时: \(String(format: "%.2f", amapDuration))秒)")
                amapFailureCount += 1
            }
            
            // 测试腾讯API
            print("🧪 🗺️ 测试腾讯API...")
            let tencentStartTime = Date()
            if let tencentResult = await tryTencentGeocoding(coordinate: coordinate, coordinateKey: coordinateKey(coordinate)) {
                let tencentDuration = Date().timeIntervalSince(tencentStartTime)
                print("🧪 ✅ 腾讯API成功: \(tencentResult.city ?? "未知") - \(tencentResult.address ?? "未知") (耗时: \(String(format: "%.2f", tencentDuration))秒)")
                tencentSuccessCount += 1
            } else {
                let tencentDuration = Date().timeIntervalSince(tencentStartTime)
                print("🧪 ❌ 腾讯API失败 (耗时: \(String(format: "%.2f", tencentDuration))秒)")
                tencentFailureCount += 1
            }
            
            print("🧪 === \(name) 测试完成 ===")
            print("")
            
            // 添加延迟避免过快请求
            try? await Task.sleep(nanoseconds: 1_000_000_000) // 1秒
        }
        
        print("🧪 === 测试结果统计 ===")
        print("🧪 高德API: 成功 \(amapSuccessCount) 次，失败 \(amapFailureCount) 次，成功率 \(String(format: "%.1f", Double(amapSuccessCount) / Double(amapSuccessCount + amapFailureCount) * 100))%")
        print("🧪 腾讯API: 成功 \(tencentSuccessCount) 次，失败 \(tencentFailureCount) 次，成功率 \(String(format: "%.1f", Double(tencentSuccessCount) / Double(tencentSuccessCount + tencentFailureCount) * 100))%")
        print("🧪 === 测试完成 ===")
    }
    
    /// 测试腾讯API签名修复
    func testTencentAPISignatureFix() async {
        print("🔐 === 开始测试腾讯API签名修复 ===")
        
        // 准备5个测试坐标
        let testCoordinates = [
            ("北京天安门", CLLocationCoordinate2D(latitude: 39.9042, longitude: 116.4074)),
            ("上海外滩", CLLocationCoordinate2D(latitude: 31.2304, longitude: 121.4737)),
            ("广州塔", CLLocationCoordinate2D(latitude: 23.1066, longitude: 113.3213)),
            ("深圳世界之窗", CLLocationCoordinate2D(latitude: 22.5405, longitude: 113.9344)),
            ("杭州西湖", CLLocationCoordinate2D(latitude: 30.2741, longitude: 120.1551))
        ]
        
        print("🔐 测试坐标列表:")
        for (index, (name, coordinate)) in testCoordinates.enumerated() {
            print("🔐 \(index + 1). \(name): \(coordinate.latitude), \(coordinate.longitude)")
        }
        print("")
        
        var successCount = 0
        var failureCount = 0
        
        for (index, (name, coordinate)) in testCoordinates.enumerated() {
            print("🔐 === 测试 \(index + 1)/5: \(name) ===")
            print("🔐 坐标: \(coordinate.latitude), \(coordinate.longitude)")
            
            let startTime = Date()
            if let result = await tryTencentGeocoding(coordinate: coordinate, coordinateKey: coordinateKey(coordinate)) {
                let duration = Date().timeIntervalSince(startTime)
                print("🔐 ✅ 腾讯API成功: \(result.city ?? "未知") - \(result.address ?? "未知") (耗时: \(String(format: "%.2f", duration))秒)")
                successCount += 1
            } else {
                let duration = Date().timeIntervalSince(startTime)
                print("🔐 ❌ 腾讯API失败 (耗时: \(String(format: "%.2f", duration))秒)")
                failureCount += 1
            }
            
            print("🔐 === \(name) 测试完成 ===")
            print("")
            
            // 添加延迟避免过快请求
            try? await Task.sleep(nanoseconds: 1_000_000_000) // 1秒
        }
        
        print("🔐 === 签名修复测试结果 ===")
        print("🔐 成功: \(successCount) 次，失败: \(failureCount) 次")
        print("🔐 成功率: \(String(format: "%.1f", Double(successCount) / Double(successCount + failureCount) * 100))%")
        print("🔐 === 测试完成 ===")
    }
    
    /// 批量解析未知地址照片（多线程版本）
    func batchParseUnknownPhotosConcurrent(count: Int, maxConcurrency: Int = 5) async {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
        let startTime = Date()
        let startTimestamp = formatter.string(from: startTime)
        print("🚀 [开始] 多线程批量解析 \(count) 张照片，时间: \(startTimestamp)")
        print("🚀 并发数: \(maxConcurrency)")
        
        // 🎯 修复：找到所有需要解析的照片（与LocationGroupService保持一致）
        let photosWithLocation = photos.filter { $0.location != nil }
        let unknownPhotos = photosWithLocation.filter { photo in
            guard let location = photo.location else { return false }
            // 位置信息不完整（未知国家/城市）
            let hasIncompleteCountry = location.country == nil || location.country == "未知国家" || location.country == "未知"
            let hasIncompleteCity = location.city == nil || location.city == "未知城市" || location.city == "未知"
            
            return hasIncompleteCountry || hasIncompleteCity
        }
        
        print("🚀 找到 \(unknownPhotos.count) 张未知地址照片")
        
        if unknownPhotos.isEmpty {
            print("🚀 没有找到需要解析的照片")
            return
        }
        
        // 限制处理数量
        let photosToProcess = Array(unknownPhotos.prefix(count))
        print("🚀 将处理前 \(photosToProcess.count) 张照片")
        
        // 设置进度跟踪
        await MainActor.run {
            self.isGeocodingInProgress = true
            self.geocodingProgress = 0.0
            self.geocodingCurrentPhoto = 0
            self.geocodingTotalPhotos = photosToProcess.count
        }
        
        // 线程安全的计数器
        let counters = GeocodingCounters()
        
        // 🚀 新增：分阶段统计变量
        var stage1StartTime = Date()
        var stage1EndTime = Date()
        var stage2StartTime = Date()
        var stage2EndTime = Date()
        var stage3StartTime = Date()
        var stage3EndTime = Date()
        var stage4StartTime = Date()
        var stage4EndTime = Date()
        var stage5StartTime = Date()
        var stage5EndTime = Date()
        
        // 🚀 新增：分阶段处理照片
        var remainingPhotos = photosToProcess
        
        // 第一阶段：已知地址和缓存检查
        print("🚀 === 第一阶段：已知地址和缓存检查（高并发）===")
        print("🚀 启动线程数: \(remainingPhotos.count) 个（无限制并发）")
        stage1StartTime = Date()
        remainingPhotos = await processPhotosWithKnownAddressAndCache(remainingPhotos, counters: counters)
        stage1EndTime = Date()
        let stage1Duration = stage1EndTime.timeIntervalSince(stage1StartTime)
        print("🚀 第一阶段完成，耗时: \(String(format: "%.2f", stage1Duration))秒，剩余照片: \(remainingPhotos.count)")
        
        // 第二阶段：苹果解析
        if !remainingPhotos.isEmpty {
            print("🚀 === 第二阶段：苹果解析（高并发）===")
            print("🚀 启动线程数: \(remainingPhotos.count) 个（无限制并发）")
            stage2StartTime = Date()
            remainingPhotos = await processPhotosWithAppleGeocoding(remainingPhotos, counters: counters)
            stage2EndTime = Date()
            let stage2Duration = stage2EndTime.timeIntervalSince(stage2StartTime)
            print("🚀 第二阶段完成，耗时: \(String(format: "%.2f", stage2Duration))秒，剩余照片: \(remainingPhotos.count)")
        }
        
        // 第三阶段：腾讯解析
        if !remainingPhotos.isEmpty {
            print("🚀 === 第三阶段：腾讯解析（最多\(maxConcurrency)线程）===")
            print("🚀 启动线程数: \(min(remainingPhotos.count, maxConcurrency)) 个（限制并发）")
            stage3StartTime = Date()
            remainingPhotos = await processPhotosWithTencentGeocoding(remainingPhotos, maxConcurrency: maxConcurrency, counters: counters)
            stage3EndTime = Date()
            let stage3Duration = stage3EndTime.timeIntervalSince(stage3StartTime)
            print("🚀 第三阶段完成，耗时: \(String(format: "%.2f", stage3Duration))秒，剩余照片: \(remainingPhotos.count)")
        }
        
        // 第四阶段：高德解析
        if !remainingPhotos.isEmpty {
            print("🚀 === 第四阶段：高德解析（最多\(maxConcurrency)线程）===")
            print("🚀 启动线程数: \(min(remainingPhotos.count, maxConcurrency)) 个（限制并发）")
            stage4StartTime = Date()
            remainingPhotos = await processPhotosWithAMapGeocoding(remainingPhotos, maxConcurrency: maxConcurrency, counters: counters)
            stage4EndTime = Date()
            let stage4Duration = stage4EndTime.timeIntervalSince(stage4StartTime)
            print("🚀 第四阶段完成，耗时: \(String(format: "%.2f", stage4Duration))秒，剩余照片: \(remainingPhotos.count)")
        }
        
        // 第五阶段：OpenStreet解析
        if !remainingPhotos.isEmpty {
            print("🚀 === 第五阶段：OpenStreet解析（高并发）===")
            print("🚀 启动线程数: \(remainingPhotos.count) 个（无限制并发）")
            stage5StartTime = Date()
            remainingPhotos = await processPhotosWithOSMGeocoding(remainingPhotos, counters: counters)
            stage5EndTime = Date()
            let stage5Duration = stage5EndTime.timeIntervalSince(stage5StartTime)
            print("🚀 第五阶段完成，耗时: \(String(format: "%.2f", stage5Duration))秒，剩余照片: \(remainingPhotos.count)")
        }
        
        // 🎯 修复：标记剩余照片为无法识别（添加验证逻辑）
        if !remainingPhotos.isEmpty {
            print("🚀 === 标记剩余照片为无法识别 ===")
            
            // 🎯 新增：验证剩余照片是否真的需要标记为无法识别
            var actuallyUnrecognizedPhotos: [PhotoData] = []
            for photo in remainingPhotos {
                guard let location = photo.location else { continue }
                
                // 检查是否已经成功解析（有国家和城市信息）
                let hasValidCountry = location.country != nil && location.country != "未知国家" && location.country != "未知"
                let hasValidCity = location.city != nil && location.city != "未知城市" && location.city != "未知"
                
                if hasValidCountry && hasValidCity {
                    print("🚀 ⚠️ 发现已成功解析的照片被错误标记: \(photo.id)")
                    continue // 跳过已成功解析的照片
                }
                
                actuallyUnrecognizedPhotos.append(photo)
            }
            
            print("🚀 验证结果: 原始剩余照片 \(remainingPhotos.count) 张，实际需要标记 \(actuallyUnrecognizedPhotos.count) 张")
            
            for photo in actuallyUnrecognizedPhotos {
                await markPhotoAsUnrecognized(photo)
                await MainActor.run {
                    counters.incrementFailure()
                }
            }
            print("🚀 标记完成，无法识别照片: \(actuallyUnrecognizedPhotos.count) 张")
        }
        
        let endTime = Date()
        let endTimestamp = formatter.string(from: endTime)
        let duration = endTime.timeIntervalSince(startTime)
        print("🚀 [结束] 多线程批量解析 \(count) 张照片，时间: \(endTimestamp)")
        print("🚀 总耗时: \(String(format: "%.2f", duration)) 秒")
        
        await MainActor.run {
            self.isGeocodingInProgress = false
            self.geocodingProgress = 1.0
        }
        
        // 保存所有数据
        saveAddressCache()
        savePhotoDataMap()
        
        print("🚀 === 多线程批量解析完成 ===")
        print("🚀 总耗时: \(String(format: "%.2f", duration)) 秒")
        print("🚀 处理照片数: \(photosToProcess.count)")
        print("🚀 成功解析: \(counters.successCount) 张")
        print("🚀 解析失败: \(counters.failureCount) 张")
        print("🚀 已知地址命中: \(counters.knownAddressHitCount) 次")
        print("🚀 缓存命中: \(counters.cacheHitCount) 次")
        print("🚀 API调用: \(counters.apiCallCount) 次")
        print("🚀 API解析分布:")
        print("   - Apple: \(counters.appleSuccessCount) 次")
        print("   - Google: \(counters.googleSuccessCount) 次")
        print("   - 高德: \(counters.amapSuccessCount) 次")
        print("   - 腾讯: \(counters.tencentSuccessCount) 次")
        print("   - OpenStreetMap: \(counters.osmSuccessCount) 次")
        print("   - API失败: \(counters.apiFailureCount) 次")
        
        // 🚀 新增：详细性能分析
        print("🚀 === 详细性能分析 ===")
        let totalPhotos = photosToProcess.count
        let successRate = Double(counters.successCount) / Double(totalPhotos) * 100
        let avgTimePerPhoto = duration / Double(totalPhotos)
        let cacheHitRate = Double(counters.cacheHitCount + counters.knownAddressHitCount) / Double(totalPhotos) * 100
        
        print("🚀 成功率: \(String(format: "%.1f", successRate))%")
        print("🚀 平均每张照片耗时: \(String(format: "%.3f", avgTimePerPhoto))秒")
        print("🚀 缓存命中率: \(String(format: "%.1f", cacheHitRate))%")
        print("🚀 实际API调用率: \(String(format: "%.1f", Double(counters.apiCallCount) / Double(totalPhotos) * 100))%")
        
        // 计算各阶段耗时占比
        let stage1DurationForAnalysis = stage1EndTime.timeIntervalSince(stage1StartTime)
        let stage1Percentage = stage1DurationForAnalysis / duration * 100
        print("🚀 第一阶段耗时占比: \(String(format: "%.1f", stage1Percentage))%")
        
        let stage2Duration = stage2EndTime.timeIntervalSince(stage2StartTime)
        if stage2Duration > 0 {
            let stage2Percentage = stage2Duration / duration * 100
            print("🚀 第二阶段耗时占比: \(String(format: "%.1f", stage2Percentage))%")
        }
        
        let stage3Duration = stage3EndTime.timeIntervalSince(stage3StartTime)
        if stage3Duration > 0 {
            let stage3Percentage = stage3Duration / duration * 100
            print("🚀 第三阶段耗时占比: \(String(format: "%.1f", stage3Percentage))%")
        }
        
        let stage4Duration = stage4EndTime.timeIntervalSince(stage4StartTime)
        if stage4Duration > 0 {
            let stage4Percentage = stage4Duration / duration * 100
            print("🚀 第四阶段耗时占比: \(String(format: "%.1f", stage4Percentage))%")
        }
        
        let stage5Duration = stage5EndTime.timeIntervalSince(stage5StartTime)
        if stage5Duration > 0 {
            let stage5Percentage = stage5Duration / duration * 100
            print("🚀 第五阶段耗时占比: \(String(format: "%.1f", stage5Percentage))%")
        }
        
        // 发送刷新通知
        NotificationCenter.default.post(name: NSNotification.Name("RefreshLocationAxis"), object: nil)
        print("🚀 已发送刷新通知")
    }
    
    /// 线程安全的计数器
    @MainActor
    private class GeocodingCounters: Sendable {
        private var _successCount = 0
        private var _failureCount = 0
        private var _knownAddressHitCount = 0
        private var _cacheHitCount = 0
        private var _apiCallCount = 0
        private var _appleSuccessCount = 0
        private var _googleSuccessCount = 0
        private var _amapSuccessCount = 0
        private var _tencentSuccessCount = 0
        private var _osmSuccessCount = 0
        private var _apiFailureCount = 0
        
        var successCount: Int { _successCount }
        var failureCount: Int { _failureCount }
        var knownAddressHitCount: Int { _knownAddressHitCount }
        var cacheHitCount: Int { _cacheHitCount }
        var apiCallCount: Int { _apiCallCount }
        var appleSuccessCount: Int { _appleSuccessCount }
        var googleSuccessCount: Int { _googleSuccessCount }
        var amapSuccessCount: Int { _amapSuccessCount }
        var tencentSuccessCount: Int { _tencentSuccessCount }
        var osmSuccessCount: Int { _osmSuccessCount }
        var apiFailureCount: Int { _apiFailureCount }
        
        func incrementSuccess() { _successCount += 1 }
        func incrementFailure() { _failureCount += 1 }
        func incrementKnownAddressHit() { _knownAddressHitCount += 1 }
        func incrementCacheHit() { _cacheHitCount += 1 }
        func incrementApiCall() { _apiCallCount += 1 }
        func incrementAppleSuccess() { _appleSuccessCount += 1 }
        func incrementGoogleSuccess() { _googleSuccessCount += 1 }
        func incrementAmapSuccess() { _amapSuccessCount += 1 }
        func incrementTencentSuccess() { _tencentSuccessCount += 1 }
        func incrementOsmSuccess() { _osmSuccessCount += 1 }
        func incrementApiFailure() { _apiFailureCount += 1 }
    }
    
    /// 处理单张照片
    private func processSinglePhoto(_ photo: PhotoData, index: Int, total: Int, counters: GeocodingCounters) async {
        // 🚀 性能优化：减少日志输出频率
        let shouldLog = index % 10 == 0 || index == total - 1 // 每10张或最后一张才打印
        
        if shouldLog {
            let now = Date()
            let formatter = DateFormatter()
            formatter.dateFormat = "HH:mm:ss"
            let timestamp = formatter.string(from: now)
            print("🚀 [\(timestamp)] 处理第 \(index + 1)/\(total) 张照片")
        }
        
        guard let location = photo.location else {
            if shouldLog {
                print("🚀 照片没有地理坐标信息，跳过")
            }
            await MainActor.run {
                counters.incrementFailure()
            }
            return
        }
        
        let coordinate = location.coordinate
        let coordinateKey = coordinateKey(coordinate)
        
        // 1. 检查已知解析地址
        if let matchingAddress = findMatchingKnownAddress(for: coordinate) {
            if shouldLog {
                print("🚀 ✅ 已知地址命中: \(matchingAddress.address ?? "无地址")")
            }
            let locationInfo = convertKnownAddressToLocationInfo(matchingAddress)
            
            // 保存到地址缓存
            let serializableLocationInfo = SerializableLocationInfo(from: locationInfo)
            addressCache[coordinateKey] = serializableLocationInfo
            saveAddressCache()
            
            await updatePhotoLocation(photo, with: locationInfo)
            await MainActor.run {
                counters.incrementKnownAddressHit()
                counters.incrementSuccess()
            }
            
            await updateProgress(index: index, total: total)
            return
        }
        
        // 2. 检查缓存
        if let cachedInfo = addressCache[coordinateKey] {
            if shouldLog {
                print("🚀 ✅ 缓存命中")
            }
            let locationInfo = cachedInfo.toLocationInfo()
            await updatePhotoLocation(photo, with: locationInfo)
            await MainActor.run {
                counters.incrementCacheHit()
                counters.incrementSuccess()
            }
            
            await updateProgress(index: index, total: total)
            return
        }
        
        // 3. 尝试API解析
        if shouldLog {
            print("🚀 🔍 开始API解析...")
        }
        await MainActor.run {
            counters.incrementApiCall()
        }
        
        let (locationInfo, usedService) = await withCheckedContinuation { continuation in
            geocodingQueue.async {
                self.geocodingSemaphore.wait()
                Task {
                    let result = await self.performGeocodingAPI(coordinate: coordinate, coordinateKey: coordinateKey)
                    self.geocodingSemaphore.signal()
                    continuation.resume(returning: result)
                }
            }
        }
        
        if let locationInfo = locationInfo, let usedService = usedService {
            if shouldLog {
                print("🚀 ✅ API解析成功 (\(usedService.displayName)): \(locationInfo.city ?? "未知")")
            }
            await MainActor.run {
                counters.incrementSuccess()
                
                // 统计每种API的成功次数
                switch usedService {
                case .apple:
                    counters.incrementAppleSuccess()
                case .google:
                    counters.incrementGoogleSuccess()
                case .amap:
                    counters.incrementAmapSuccess()
                case .tencent:
                    counters.incrementTencentSuccess()
                case .openStreetMap:
                    counters.incrementOsmSuccess()
                }
            }
        } else {
            if shouldLog {
                print("🚀 ❌ API解析失败")
            }
            await MainActor.run {
                counters.incrementFailure()
                counters.incrementApiFailure()
            }
        }
        
        await updateProgress(index: index, total: total)
    }
    
    /// 更新进度
    private func updateProgress(index: Int, total: Int) async {
        await MainActor.run {
            self.geocodingProgress = Double(index + 1) / Double(total)
            self.geocodingCurrentPhoto = index + 1
        }
    }
    
    // MARK: - 开机加载优化
    
    /// 🚀 优化：快速开机加载，直接使用持久化数据
    private func fastLoadFromPersistentData() async -> Bool {
        let fastLoadStartTime = Date()
        print("🚀 开始快速开机加载 - \(fastLoadStartTime)")
        
        guard !photoDataMap.isEmpty else {
            print("📂 持久化数据映射为空，无法快速加载")
            return false
        }
        
        print("🚀 开始快速开机加载，映射中有 \(photoDataMap.count) 条记录")
        
        // 🚀 优化：预分配数组容量，减少内存重分配
        let totalPhotos = photoDataMap.count
        var loadedPhotos = [PhotoData]()
        loadedPhotos.reserveCapacity(totalPhotos)
        
        // 🚀 优化：分批处理，减少内存压力
        let batchSize = 1000
        var validCount = 0
        var invalidCount = 0
        
        let photoIds = Array(photoDataMap.keys)
        let totalBatches = (photoIds.count + batchSize - 1) / batchSize
        
        print("🚀 分批处理：\(totalBatches) 个批次，每批 \(batchSize) 张照片")
        
        // 🚀 优化：预热第一批次，减少初始化开销
        let firstBatchIds = Array(photoIds.prefix(batchSize))
        let firstBatchStartTime = Date()
        
        for photoId in firstBatchIds {
            if let serializableData = photoDataMap[photoId],
               let photoData = serializableData.toPhotoDataWithoutAsset() {
                loadedPhotos.append(photoData)
                validCount += 1
            } else {
                invalidCount += 1
            }
        }
        
        let firstBatchTime = Date().timeIntervalSince(firstBatchStartTime)
        print("🚀 批次 1/\(totalBatches) 完成: \(validCount) 张照片，耗时 \(String(format: "%.2f", firstBatchTime)) 秒")
        
        // 🚀 优化：后续批次并行处理
        for batchIndex in 1..<totalBatches {
            let batchStartTime = Date()
            let startIndex = batchIndex * batchSize
            let endIndex = min(startIndex + batchSize, photoIds.count)
            let batchIds = Array(photoIds[startIndex..<endIndex])
            
            var batchValidCount = 0
            var batchInvalidCount = 0
            
            for photoId in batchIds {
                if let serializableData = photoDataMap[photoId],
                   let photoData = serializableData.toPhotoDataWithoutAsset() {
                    loadedPhotos.append(photoData)
                    batchValidCount += 1
                } else {
                    batchInvalidCount += 1
                }
            }
            
            validCount += batchValidCount
            invalidCount += batchInvalidCount
            
            let batchTime = Date().timeIntervalSince(batchStartTime)
            print("🚀 批次 \(batchIndex + 1)/\(totalBatches) 完成: \(batchValidCount) 张照片，耗时 \(String(format: "%.2f", batchTime)) 秒")
            
            // 🚀 优化：每5个批次清理一次内存
            if (batchIndex + 1) % 5 == 0 {
                let memoryBefore = getMemoryUsage()
                print("💾 内存清理开始，当前使用: \(memoryBefore) MB")
                await cleanupMemory()
                let memoryAfter = getMemoryUsage()
                print("💾 内存清理完成，当前使用: \(memoryAfter) MB")
            }
        }
        
        let fastLoadEndTime = Date()
        let fastLoadTime = fastLoadEndTime.timeIntervalSince(fastLoadStartTime)
        
        print("🚀 快速加载完成: \(validCount) 张有效照片，\(invalidCount) 张无效")
        print("⏱️ 快速加载内部耗时: \(String(format: "%.2f", fastLoadTime)) 秒")
        
        // 🚀 优化：批量设置photos数组，减少UI更新次数
        await MainActor.run {
            self.photos = loadedPhotos
        }
        
        return true
    }
    
    /// 🚀 获取LocationGroupService实例
    private func getLocationGroupService() -> LocationGroupService? {
        // 通过通知中心发送消息，让LocationGroupService加载持久化数据
        NotificationCenter.default.post(name: NSNotification.Name("LoadPersistentGroups"), object: nil)
        return nil // 不需要返回实例，通过通知中心通信
    }
    
    /// 优化版多线程批量解析（按API特点分层处理）
    func batchParseUnknownPhotosOptimized(count: Int) async {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
        let startTime = Date()
        let startTimestamp = formatter.string(from: startTime)
        print("🚀 [开始] 优化版多线程批量解析 \(count) 张照片，时间: \(startTimestamp)")
        
        // 🎯 修复：解析前统计待识别照片数量（与LocationGroupService保持一致）
        let unknownPhotosBefore = photos.filter { photo in
            guard let location = photo.location else { return true }
            // 成功解析的照片：有国家和城市信息，且不是"未知"值
            let hasCountry = location.country != nil && location.country != "未知国家" && location.country != "未知"
            let hasCity = location.city != nil && location.city != "未知城市" && location.city != "未知"
            let hasAddress = location.address != nil && location.address != "未知地点" && location.address != "未知"
            
            // 必须有国家和城市信息，地址信息可选
            return !hasCountry || !hasCity
        }
        print("🚀 [解析前] 待识别照片数量: \(unknownPhotosBefore.count)")
        
        // 🎯 修复：找到所有需要解析的照片（与LocationGroupService保持一致）
        let photosWithLocation = photos.filter { $0.location != nil }
        let unknownPhotos = photosWithLocation.filter { photo in
            guard let location = photo.location else { return false }
            // 位置信息不完整（未知国家/城市）
            let hasIncompleteCountry = location.country == nil || location.country == "未知国家" || location.country == "未知"
            let hasIncompleteCity = location.city == nil || location.city == "未知城市" || location.city == "未知"
            
            return hasIncompleteCountry || hasIncompleteCity
        }
        
        print("🚀 找到 \(unknownPhotos.count) 张未知地址照片")
        
        if unknownPhotos.isEmpty {
            print("🚀 没有找到需要解析的照片")
            return
        }
        
        // 限制处理数量
        var photosToProcess = Array(unknownPhotos.prefix(count))
        print("🚀 将处理前 \(photosToProcess.count) 张照片")
        
        // 设置进度跟踪
        await MainActor.run {
            self.isGeocodingInProgress = true
            self.geocodingProgress = 0.0
            self.geocodingCurrentPhoto = 0
            self.geocodingTotalPhotos = photosToProcess.count
        }
        
        // 线程安全的计数器
        let counters = GeocodingCounters()
        
        // 声明各阶段的时间变量
        var stage1StartTime = Date()
        var stage1EndTime = Date()
        var stage2StartTime = Date()
        var stage2EndTime = Date()
        var stage3StartTime = Date()
        var stage3EndTime = Date()
        var stage4StartTime = Date()
        var stage4EndTime = Date()
        var stage5StartTime = Date()
        var stage5EndTime = Date()
        
        // 第一阶段：已知地址和缓存检查（高并发，无限制）
        print("🚀 === 第一阶段：已知地址和缓存检查（高并发）===")
        print("🚀 启动线程数: \(photosToProcess.count) 个（无限制并发）")
        stage1StartTime = Date()
        
        // 🚀 新增：第一阶段详细统计
        var stage1KnownAddressTotalTime: TimeInterval = 0
        var stage1CacheCheckTotalTime: TimeInterval = 0
        var stage1UpdateTotalTime: TimeInterval = 0
        var stage1KnownAddressCount = 0
        var stage1CacheHitCount = 0
        
        photosToProcess = await processPhotosWithKnownAddressAndCacheDetailed(
            photosToProcess, 
            counters: counters,
            knownAddressTotalTime: &stage1KnownAddressTotalTime,
            cacheCheckTotalTime: &stage1CacheCheckTotalTime,
            updateTotalTime: &stage1UpdateTotalTime,
            knownAddressCount: &stage1KnownAddressCount,
            cacheHitCount: &stage1CacheHitCount
        )
        
        stage1EndTime = Date()
        let stage1Duration = stage1EndTime.timeIntervalSince(stage1StartTime)
        print("🚀 第一阶段完成，耗时: \(String(format: "%.2f", stage1Duration))秒，剩余照片: \(photosToProcess.count)")
        
        // 🚀 新增：第一阶段详细耗时分析
        print("🚀 === 第一阶段详细耗时分析 ===")
        let avgKnownAddressTime = stage1KnownAddressCount > 0 ? stage1KnownAddressTotalTime / Double(stage1KnownAddressCount) : 0
        let avgCacheCheckTime = stage1CacheHitCount > 0 ? stage1CacheCheckTotalTime / Double(stage1CacheHitCount) : 0
        let avgUpdateTime = (stage1KnownAddressCount + stage1CacheHitCount) > 0 ? stage1UpdateTotalTime / Double(stage1KnownAddressCount + stage1CacheHitCount) : 0
        
        print("🚀 已知地址检查: 总耗时 \(String(format: "%.3f", stage1KnownAddressTotalTime))秒, 处理 \(stage1KnownAddressCount) 张, 平均 \(String(format: "%.3f", avgKnownAddressTime))秒/张")
        print("🚀 缓存检查: 总耗时 \(String(format: "%.3f", stage1CacheCheckTotalTime))秒, 处理 \(stage1CacheHitCount) 张, 平均 \(String(format: "%.3f", avgCacheCheckTime))秒/张")
        print("🚀 照片更新: 总耗时 \(String(format: "%.3f", stage1UpdateTotalTime))秒, 处理 \(stage1KnownAddressCount + stage1CacheHitCount) 张, 平均 \(String(format: "%.3f", avgUpdateTime))秒/张")
        
        let knownAddressPercentage = stage1Duration > 0 ? stage1KnownAddressTotalTime / stage1Duration * 100 : 0
        let cacheCheckPercentage = stage1Duration > 0 ? stage1CacheCheckTotalTime / stage1Duration * 100 : 0
        let updatePercentage = stage1Duration > 0 ? stage1UpdateTotalTime / stage1Duration * 100 : 0
        
        print("🚀 耗时占比: 已知地址检查 \(String(format: "%.1f", knownAddressPercentage))%, 缓存检查 \(String(format: "%.1f", cacheCheckPercentage))%, 照片更新 \(String(format: "%.1f", updatePercentage))%")
        
        // 第二阶段：苹果解析（高并发，无限制）
        if !photosToProcess.isEmpty {
            print("🚀 === 第二阶段：苹果解析（高并发）===")
            print("🚀 启动线程数: \(photosToProcess.count) 个（无限制并发）")
            stage2StartTime = Date()
            photosToProcess = await processPhotosWithAppleGeocoding(photosToProcess, counters: counters)
            stage2EndTime = Date()
            let stage2Duration = stage2EndTime.timeIntervalSince(stage2StartTime)
            print("🚀 第二阶段完成，耗时: \(String(format: "%.2f", stage2Duration))秒，剩余照片: \(photosToProcess.count)")
        }
        
        // 第三阶段：腾讯解析（最多5线程）
        if !photosToProcess.isEmpty {
            print("🚀 === 第三阶段：腾讯解析（最多5线程）===")
            print("🚀 启动线程数: \(min(photosToProcess.count, 5)) 个（限制并发）")
            stage3StartTime = Date()
            photosToProcess = await processPhotosWithTencentGeocoding(photosToProcess, maxConcurrency: 5, counters: counters)
            stage3EndTime = Date()
            let stage3Duration = stage3EndTime.timeIntervalSince(stage3StartTime)
            print("🚀 第三阶段完成，耗时: \(String(format: "%.2f", stage3Duration))秒，剩余照片: \(photosToProcess.count)")
        }
        
        // 第四阶段：高德解析（最多5线程）
        if !photosToProcess.isEmpty {
            print("🚀 === 第四阶段：高德解析（最多5线程）===")
            print("🚀 启动线程数: \(min(photosToProcess.count, 5)) 个（限制并发）")
            stage4StartTime = Date()
            photosToProcess = await processPhotosWithAMapGeocoding(photosToProcess, maxConcurrency: 5, counters: counters)
            stage4EndTime = Date()
            let stage4Duration = stage4EndTime.timeIntervalSince(stage4StartTime)
            print("🚀 第四阶段完成，耗时: \(String(format: "%.2f", stage4Duration))秒，剩余照片: \(photosToProcess.count)")
        }
        
        // 第五阶段：OpenStreet解析（高并发，无限制）
        if !photosToProcess.isEmpty {
            print("🚀 === 第五阶段：OpenStreet解析（高并发）===")
            print("🚀 启动线程数: \(photosToProcess.count) 个（无限制并发）")
            stage5StartTime = Date()
            photosToProcess = await processPhotosWithOSMGeocoding(photosToProcess, counters: counters)
            stage5EndTime = Date()
            let stage5Duration = stage5EndTime.timeIntervalSince(stage5StartTime)
            print("🚀 第五阶段完成，耗时: \(String(format: "%.2f", stage5Duration))秒，剩余照片: \(photosToProcess.count)")
        }
        
        // 🎯 修复：标记剩余照片为无法识别（添加验证逻辑）
        if !photosToProcess.isEmpty {
            print("🚀 === 标记剩余照片为无法识别 ===")
            
            // 🎯 新增：验证剩余照片是否真的需要标记为无法识别
            var actuallyUnrecognizedPhotos: [PhotoData] = []
            for photo in photosToProcess {
                guard let location = photo.location else { continue }
                
                // 检查是否已经成功解析（有国家和城市信息）
                let hasValidCountry = location.country != nil && location.country != "未知国家" && location.country != "未知"
                let hasValidCity = location.city != nil && location.city != "未知城市" && location.city != "未知"
                
                if hasValidCountry && hasValidCity {
                    print("🚀 ⚠️ 发现已成功解析的照片被错误标记: \(photo.id)")
                    continue // 跳过已成功解析的照片
                }
                
                actuallyUnrecognizedPhotos.append(photo)
            }
            
            print("🚀 验证结果: 原始剩余照片 \(photosToProcess.count) 张，实际需要标记 \(actuallyUnrecognizedPhotos.count) 张")
            
            for photo in actuallyUnrecognizedPhotos {
                await markPhotoAsUnrecognized(photo)
                await MainActor.run {
                    counters.incrementFailure()
                }
            }
            print("🚀 标记完成，无法识别照片: \(actuallyUnrecognizedPhotos.count) 张")
        }
        
        let endTime = Date()
        let endTimestamp = formatter.string(from: endTime)
        let duration = endTime.timeIntervalSince(startTime)
        print("🚀 [结束] 优化版多线程批量解析 \(count) 张照片，时间: \(endTimestamp)")
        print("🚀 总耗时: \(String(format: "%.2f", duration)) 秒")
        
        await MainActor.run {
            self.isGeocodingInProgress = false
            self.geocodingProgress = 1.0
        }
        
        // 保存所有数据
        saveAddressCache()
        savePhotoDataMap()
        
        // 🚀 性能优化：批量处理完成后统一清除缓存和发送通知
        await MainActor.run {
            // 清除地点轴缓存，强制重新计算
            self.cachedLocationGroups = []
            self.lastPhotoCount = 0
            self.lastDataFingerprint = ""
            
            // 发送刷新通知，强制UI更新
            NotificationCenter.default.post(name: NSNotification.Name("RefreshLocationAxis"), object: nil)
            print("🚀 已清除缓存并发送刷新通知")
        }
        
        print("🚀 === 优化版多线程批量解析完成 ===")
        print("🚀 总耗时: \(String(format: "%.2f", duration)) 秒")
        print("🚀 处理照片数: \(count)")
        print("🚀 成功解析: \(counters.successCount) 张")
        print("🚀 解析失败: \(counters.failureCount) 张")
        print("🚀 已知地址命中: \(counters.knownAddressHitCount) 次")
        print("🚀 缓存命中: \(counters.cacheHitCount) 次")
        print("🚀 API调用: \(counters.apiCallCount) 次")
        print("🚀 API解析分布:")
        print("   - Apple: \(counters.appleSuccessCount) 次")
        print("   - Google: \(counters.googleSuccessCount) 次")
        print("   - 高德: \(counters.amapSuccessCount) 次")
        print("   - 腾讯: \(counters.tencentSuccessCount) 次")
        print("   - OpenStreetMap: \(counters.osmSuccessCount) 次")
        print("   - API失败: \(counters.apiFailureCount) 次")
        
        // 🚀 新增：详细性能分析
        print("🚀 === 详细性能分析 ===")
        let totalPhotos = count
        let successRate = Double(counters.successCount) / Double(totalPhotos) * 100
        let avgTimePerPhoto = duration / Double(totalPhotos)
        let cacheHitRate = Double(counters.cacheHitCount + counters.knownAddressHitCount) / Double(totalPhotos) * 100
        
        print("🚀 成功率: \(String(format: "%.1f", successRate))%")
        print("🚀 平均每张照片耗时: \(String(format: "%.3f", avgTimePerPhoto))秒")
        print("🚀 缓存命中率: \(String(format: "%.1f", cacheHitRate))%")
        print("🚀 实际API调用率: \(String(format: "%.1f", Double(counters.apiCallCount) / Double(totalPhotos) * 100))%")
        
        // 🚀 新增：各阶段耗时统计
        print("🚀 === 各阶段耗时统计 ===")
        let stage1DurationForAnalysis = stage1EndTime.timeIntervalSince(stage1StartTime)
        let stage1Percentage = stage1DurationForAnalysis / duration * 100
        print("🚀 第一阶段（已知地址和缓存检查）: \(String(format: "%.2f", stage1DurationForAnalysis))秒 (\(String(format: "%.1f", stage1Percentage))%)")
        
        let stage2DurationForAnalysis = stage2EndTime.timeIntervalSince(stage2StartTime)
        if stage2DurationForAnalysis > 0 {
            let stage2Percentage = stage2DurationForAnalysis / duration * 100
            print("🚀 第二阶段（苹果解析）: \(String(format: "%.2f", stage2DurationForAnalysis))秒 (\(String(format: "%.1f", stage2Percentage))%)")
        }
        
        let stage3DurationForAnalysis = stage3EndTime.timeIntervalSince(stage3StartTime)
        if stage3DurationForAnalysis > 0 {
            let stage3Percentage = stage3DurationForAnalysis / duration * 100
            print("🚀 第三阶段（腾讯解析）: \(String(format: "%.2f", stage3DurationForAnalysis))秒 (\(String(format: "%.1f", stage3Percentage))%)")
        }
        
        let stage4DurationForAnalysis = stage4EndTime.timeIntervalSince(stage4StartTime)
        if stage4DurationForAnalysis > 0 {
            let stage4Percentage = stage4DurationForAnalysis / duration * 100
            print("🚀 第四阶段（高德解析）: \(String(format: "%.2f", stage4DurationForAnalysis))秒 (\(String(format: "%.1f", stage4Percentage))%)")
        }
        
        let stage5DurationForAnalysis = stage5EndTime.timeIntervalSince(stage5StartTime)
        if stage5DurationForAnalysis > 0 {
            let stage5Percentage = stage5DurationForAnalysis / duration * 100
            print("🚀 第五阶段（OpenStreet解析）: \(String(format: "%.2f", stage5DurationForAnalysis))秒 (\(String(format: "%.1f", stage5Percentage))%)")
        }
        
        // 🚀 新增：解析后统计待识别照片数量
        let unknownPhotosAfter = photos.filter { photo in
            guard let location = photo.location else { return true }
            let hasAddress = location.address != nil && location.address != "未知" && location.address != "未知地点"
            let hasCity = location.city != nil && location.city != "未知" && location.city != "未知城市"
            let hasCountry = location.country != nil && location.country != "未知" && location.country != "未知国家"
            return !hasAddress || !hasCity || !hasCountry
        }
        print("🚀 [解析后] 待识别照片数量: \(unknownPhotosAfter.count)")
        print("🚀 [变化] 待识别照片减少: \(unknownPhotosBefore.count - unknownPhotosAfter.count)")
        
        // 发送刷新通知
        NotificationCenter.default.post(name: NSNotification.Name("RefreshLocationAxis"), object: nil)
        print("🚀 已发送刷新通知")
    }
    
    /// 第一阶段：已知地址和缓存检查（高并发）
    private func processPhotosWithKnownAddressAndCache(_ photos: [PhotoData], counters: GeocodingCounters) async -> [PhotoData] {
        var remainingPhotos: [PhotoData] = []
        
        await withTaskGroup(of: (PhotoData, Bool).self) { group in
            for photo in photos {
                group.addTask {
                    return await self.processPhotoWithKnownAddressAndCache(photo, counters: counters)
                }
            }
            
            for await (photo, success) in group {
                if !success {
                    remainingPhotos.append(photo)
                }
            }
        }
        
        return remainingPhotos
    }
    
    /// 第一阶段：已知地址和缓存检查（带详细耗时统计）
    private func processPhotosWithKnownAddressAndCacheDetailed(
        _ photos: [PhotoData], 
        counters: GeocodingCounters,
        knownAddressTotalTime: inout TimeInterval,
        cacheCheckTotalTime: inout TimeInterval,
        updateTotalTime: inout TimeInterval,
        knownAddressCount: inout Int,
        cacheHitCount: inout Int
    ) async -> [PhotoData] {
        var remainingPhotos: [PhotoData] = []
        
        await withTaskGroup(of: (PhotoData, Bool, TimeInterval, TimeInterval, TimeInterval, String).self) { group in
            for photo in photos {
                group.addTask {
                    return await self.processPhotoWithKnownAddressAndCacheDetailed(
                        photo, 
                        counters: counters
                    )
                }
            }
            
            for await (photo, success, knownAddressTime, cacheCheckTime, updateTime, operationType) in group {
                if !success {
                    remainingPhotos.append(photo)
                } else {
                    // 🎯 新增：实时更新进度
                    await MainActor.run {
                        self.geocodingCurrentPhoto += 1
                        self.geocodingProgress = Double(self.geocodingCurrentPhoto) / Double(self.geocodingTotalPhotos)
                    }
                    
                    // 累计耗时统计
                    if operationType == "knownAddress" {
                        knownAddressTotalTime += knownAddressTime
                        updateTotalTime += updateTime
                        knownAddressCount += 1
                    } else if operationType == "cache" {
                        cacheCheckTotalTime += cacheCheckTime
                        updateTotalTime += updateTime
                        cacheHitCount += 1
                    }
                }
            }
        }
        
        return remainingPhotos
    }
    
    /// 处理单张照片的已知地址和缓存检查（带详细耗时统计）
    private func processPhotoWithKnownAddressAndCache(_ photo: PhotoData, counters: GeocodingCounters) async -> (PhotoData, Bool) {
        guard let location = photo.location else {
            return (photo, false)
        }
        
        let coordinate = location.coordinate
        let coordinateKey = coordinateKey(coordinate)
        
        // 🚀 新增：详细耗时统计
        let knownAddressStartTime = Date()
        
        // 检查已知解析地址
        if let matchingAddress = findMatchingKnownAddress(for: coordinate) {
            let knownAddressEndTime = Date()
            let knownAddressDuration = knownAddressEndTime.timeIntervalSince(knownAddressStartTime)
            
            let locationInfo = convertKnownAddressToLocationInfo(matchingAddress)
            
            // 保存到地址缓存（但不立即保存到文件）
            let serializableLocationInfo = SerializableLocationInfo(from: locationInfo)
            addressCache[coordinateKey] = serializableLocationInfo
            
            // 🚀 新增：照片更新耗时统计
            let updateStartTime = Date()
            await updatePhotoLocation(photo, with: locationInfo)
            let updateEndTime = Date()
            let updateDuration = updateEndTime.timeIntervalSince(updateStartTime)
            
            await MainActor.run {
                counters.incrementKnownAddressHit()
                counters.incrementSuccess()
            }
            
            // 🚀 新增：记录详细耗时（仅在调试时打印）
            if counters.knownAddressHitCount % 100 == 0 {
                print("🚀 [详细统计] 照片 \(photo.id): 已知地址检查 \(String(format: "%.3f", knownAddressDuration))秒, 照片更新 \(String(format: "%.3f", updateDuration))秒")
            }
            
            return (photo, true)
        }
        
        // 🚀 新增：缓存检查耗时统计
        let cacheStartTime = Date()
        
        // 检查缓存
        if let cachedInfo = addressCache[coordinateKey] {
            let cacheEndTime = Date()
            let cacheDuration = cacheEndTime.timeIntervalSince(cacheStartTime)
            
            let locationInfo = cachedInfo.toLocationInfo()
            
            // 🚀 新增：照片更新耗时统计
            let updateStartTime = Date()
            await updatePhotoLocation(photo, with: locationInfo)
            let updateEndTime = Date()
            let updateDuration = updateEndTime.timeIntervalSince(updateStartTime)
            
            await MainActor.run {
                counters.incrementCacheHit()
                counters.incrementSuccess()
            }
            
            // 🚀 新增：记录详细耗时（仅在调试时打印）
            if counters.cacheHitCount % 100 == 0 {
                print("🚀 [详细统计] 照片 \(photo.id): 缓存检查 \(String(format: "%.3f", cacheDuration))秒, 照片更新 \(String(format: "%.3f", updateDuration))秒")
            }
            
            return (photo, true)
        }
        
        return (photo, false)
    }
    
    /// 处理单张照片的已知地址和缓存检查（返回详细耗时统计）
    private func processPhotoWithKnownAddressAndCacheDetailed(_ photo: PhotoData, counters: GeocodingCounters) async -> (PhotoData, Bool, TimeInterval, TimeInterval, TimeInterval, String) {
        guard let location = photo.location else {
            return (photo, false, 0, 0, 0, "none")
        }
        
        let coordinate = location.coordinate
        let coordinateKey = coordinateKey(coordinate)
        
        // 🚀 新增：详细耗时统计
        let knownAddressStartTime = Date()
        
        // 检查已知解析地址
        if let matchingAddress = findMatchingKnownAddress(for: coordinate) {
            let knownAddressEndTime = Date()
            let knownAddressDuration = knownAddressEndTime.timeIntervalSince(knownAddressStartTime)
            
            let locationInfo = convertKnownAddressToLocationInfo(matchingAddress)
            
            // 保存到地址缓存（但不立即保存到文件）
            let serializableLocationInfo = SerializableLocationInfo(from: locationInfo)
            addressCache[coordinateKey] = serializableLocationInfo
            
            // 🚀 新增：照片更新耗时统计
            let updateStartTime = Date()
            await updatePhotoLocation(photo, with: locationInfo)
            let updateEndTime = Date()
            let updateDuration = updateEndTime.timeIntervalSince(updateStartTime)
            
            await MainActor.run {
                counters.incrementKnownAddressHit()
                counters.incrementSuccess()
            }
            
            return (photo, true, knownAddressDuration, 0, updateDuration, "knownAddress")
        }
        
        // 🚀 新增：缓存检查耗时统计
        let cacheStartTime = Date()
        
        // 检查缓存
        if let cachedInfo = addressCache[coordinateKey] {
            let cacheEndTime = Date()
            let cacheDuration = cacheEndTime.timeIntervalSince(cacheStartTime)
            
            let locationInfo = cachedInfo.toLocationInfo()
            
            // 🚀 新增：照片更新耗时统计
            let updateStartTime = Date()
            await updatePhotoLocation(photo, with: locationInfo)
            let updateEndTime = Date()
            let updateDuration = updateEndTime.timeIntervalSince(updateStartTime)
            
            await MainActor.run {
                counters.incrementCacheHit()
                counters.incrementSuccess()
            }
            
            return (photo, true, 0, cacheDuration, updateDuration, "cache")
        }
        
        return (photo, false, 0, 0, 0, "none")
    }
    

    
    /// 第二阶段：苹果解析（高并发）
    private func processPhotosWithAppleGeocoding(_ photos: [PhotoData], counters: GeocodingCounters) async -> [PhotoData] {
        var remainingPhotos: [PhotoData] = []
        
        await withTaskGroup(of: (PhotoData, Bool).self) { group in
            for photo in photos {
                group.addTask {
                    return await self.processPhotoWithAppleGeocoding(photo, counters: counters)
                }
            }
            
            for await (photo, success) in group {
                if !success {
                    remainingPhotos.append(photo)
                } else {
                    // 🚀 修复：苹果解析成功时实时更新进度条
                    await MainActor.run {
                        self.geocodingCurrentPhoto += 1
                        self.geocodingProgress = Double(self.geocodingCurrentPhoto) / Double(self.geocodingTotalPhotos)
                    }
                }
            }
        }
        
        return remainingPhotos
    }
    
    /// 处理单张照片的苹果解析
    private func processPhotoWithAppleGeocoding(_ photo: PhotoData, counters: GeocodingCounters) async -> (PhotoData, Bool) {
        guard let location = photo.location else {
            return (photo, false)
        }
        
        let coordinate = location.coordinate
        let coordinateKey = coordinateKey(coordinate)
        
        // 尝试苹果解析
        if let locationInfo = await performAppleGeocoding(coordinate: coordinate) {
            // 保存到地址缓存（但不立即保存到文件）
            let serializableLocationInfo = SerializableLocationInfo(from: locationInfo)
            addressCache[coordinateKey] = serializableLocationInfo
            // 🚀 性能优化：移除每次保存，改为批量保存
            // saveAddressCache()
            
            await updatePhotoLocation(photo, with: locationInfo)
            await MainActor.run {
                counters.incrementApiCall()
                counters.incrementAppleSuccess()
                counters.incrementSuccess()
            }
            return (photo, true)
        }
        
        return (photo, false)
    }
    
    /// 第三阶段：腾讯解析（限制并发数）
    private func processPhotosWithTencentGeocoding(_ photos: [PhotoData], maxConcurrency: Int, counters: GeocodingCounters) async -> [PhotoData] {
        var remainingPhotos: [PhotoData] = []
        
        await withTaskGroup(of: (PhotoData, Bool).self) { group in
            for (index, photo) in photos.enumerated() {
                group.addTask {
                    return await self.processPhotoWithTencentGeocoding(photo, counters: counters)
                }
                
                // 控制并发数
                if index % maxConcurrency == maxConcurrency - 1 {
                    for _ in 0..<maxConcurrency {
                        if let (photo, success) = await group.next() {
                            if !success {
                                remainingPhotos.append(photo)
                            } else {
                                // 🚀 修复：腾讯解析成功时实时更新进度条
                                await MainActor.run {
                                    self.geocodingCurrentPhoto += 1
                                    self.geocodingProgress = Double(self.geocodingCurrentPhoto) / Double(self.geocodingTotalPhotos)
                                }
                            }
                        }
                    }
                }
            }
            
            // 等待剩余任务完成
            for await (photo, success) in group {
                if !success {
                    remainingPhotos.append(photo)
                } else {
                    // 🚀 修复：腾讯解析成功时实时更新进度条
                    await MainActor.run {
                        self.geocodingCurrentPhoto += 1
                        self.geocodingProgress = Double(self.geocodingCurrentPhoto) / Double(self.geocodingTotalPhotos)
                    }
                }
            }
        }
        
        return remainingPhotos
    }
    
    /// 处理单张照片的腾讯解析
    private func processPhotoWithTencentGeocoding(_ photo: PhotoData, counters: GeocodingCounters) async -> (PhotoData, Bool) {
        guard let location = photo.location else {
            return (photo, false)
        }
        
        let coordinate = location.coordinate
        let coordinateKey = coordinateKey(coordinate)
        
        // 尝试腾讯解析
        if let locationInfo = await performTencentGeocoding(coordinate: coordinate) {
            // 保存到地址缓存（但不立即保存到文件）
            let serializableLocationInfo = SerializableLocationInfo(from: locationInfo)
            addressCache[coordinateKey] = serializableLocationInfo
            // 🚀 性能优化：移除每次保存，改为批量保存
            // saveAddressCache()
            
            await updatePhotoLocation(photo, with: locationInfo)
            await MainActor.run {
                counters.incrementApiCall()
                counters.incrementTencentSuccess()
                counters.incrementSuccess()
            }
            return (photo, true)
        }
        
        return (photo, false)
    }
    
    /// 第四阶段：高德解析（限制并发数）
    private func processPhotosWithAMapGeocoding(_ photos: [PhotoData], maxConcurrency: Int, counters: GeocodingCounters) async -> [PhotoData] {
        var remainingPhotos: [PhotoData] = []
        
        await withTaskGroup(of: (PhotoData, Bool).self) { group in
            for (index, photo) in photos.enumerated() {
                group.addTask {
                    return await self.processPhotoWithAMapGeocoding(photo, counters: counters)
                }
                
                // 控制并发数
                if index % maxConcurrency == maxConcurrency - 1 {
                    for _ in 0..<maxConcurrency {
                        if let (photo, success) = await group.next() {
                            if !success {
                                remainingPhotos.append(photo)
                            } else {
                                // 🚀 修复：高德解析成功时实时更新进度条
                                await MainActor.run {
                                    self.geocodingCurrentPhoto += 1
                                    self.geocodingProgress = Double(self.geocodingCurrentPhoto) / Double(self.geocodingTotalPhotos)
                                }
                            }
                        }
                    }
                }
            }
            
            // 等待剩余任务完成
            for await (photo, success) in group {
                if !success {
                    remainingPhotos.append(photo)
                } else {
                    // 🚀 修复：高德解析成功时实时更新进度条
                    await MainActor.run {
                        self.geocodingCurrentPhoto += 1
                        self.geocodingProgress = Double(self.geocodingCurrentPhoto) / Double(self.geocodingTotalPhotos)
                    }
                }
            }
        }
        
        return remainingPhotos
    }
    
    /// 处理单张照片的高德解析
    private func processPhotoWithAMapGeocoding(_ photo: PhotoData, counters: GeocodingCounters) async -> (PhotoData, Bool) {
        guard let location = photo.location else {
            return (photo, false)
        }
        
        let coordinate = location.coordinate
        let coordinateKey = coordinateKey(coordinate)
        
        // 尝试高德解析
        if let locationInfo = await performAMapGeocoding(coordinate: coordinate) {
            // 保存到地址缓存（但不立即保存到文件）
            let serializableLocationInfo = SerializableLocationInfo(from: locationInfo)
            addressCache[coordinateKey] = serializableLocationInfo
            // 🚀 性能优化：移除每次保存，改为批量保存
            // saveAddressCache()
            
            await updatePhotoLocation(photo, with: locationInfo)
            await MainActor.run {
                counters.incrementApiCall()
                counters.incrementAmapSuccess()
                counters.incrementSuccess()
            }
            return (photo, true)
        }
        
        return (photo, false)
    }
    
    /// 第五阶段：OpenStreet解析（高并发）
    private func processPhotosWithOSMGeocoding(_ photos: [PhotoData], counters: GeocodingCounters) async -> [PhotoData] {
        var remainingPhotos: [PhotoData] = []
        
        await withTaskGroup(of: (PhotoData, Bool).self) { group in
            for photo in photos {
                group.addTask {
                    return await self.processPhotoWithOSMGeocoding(photo, counters: counters)
                }
            }
            
            for await (photo, success) in group {
                if !success {
                    remainingPhotos.append(photo)
                } else {
                    // 🚀 修复：OpenStreetMap解析成功时实时更新进度条
                    await MainActor.run {
                        self.geocodingCurrentPhoto += 1
                        self.geocodingProgress = Double(self.geocodingCurrentPhoto) / Double(self.geocodingTotalPhotos)
                    }
                }
            }
        }
        
        return remainingPhotos
    }
    
    /// 处理单张照片的OpenStreet解析
    private func processPhotoWithOSMGeocoding(_ photo: PhotoData, counters: GeocodingCounters) async -> (PhotoData, Bool) {
        guard let location = photo.location else {
            return (photo, false)
        }
        
        let coordinate = location.coordinate
        let coordinateKey = coordinateKey(coordinate)
        
        // 尝试OpenStreet解析
        if let locationInfo = await performOSMGeocoding(coordinate: coordinate) {
            // 保存到地址缓存（但不立即保存到文件）
            let serializableLocationInfo = SerializableLocationInfo(from: locationInfo)
            addressCache[coordinateKey] = serializableLocationInfo
            // 🚀 性能优化：移除每次保存，改为批量保存
            // saveAddressCache()
            
            await updatePhotoLocation(photo, with: locationInfo)
            await MainActor.run {
                counters.incrementApiCall()
                counters.incrementOsmSuccess()
                counters.incrementSuccess()
            }
            return (photo, true)
        }
        
        return (photo, false)
    }
    
    /// 标记照片为无法识别
    private func markPhotoAsUnrecognized(_ photo: PhotoData) async {
        guard let location = photo.location else { return }
        
        let unrecognizedLocationInfo = LocationInfo(
            coordinate: location.coordinate,
            country: "未知国家",
            state: "未知州/省",
            city: "未知城市",
            address: "未知地点"
        )
        
        await updatePhotoLocation(photo, with: unrecognizedLocationInfo)
    }
    
    /// 苹果地理编码
    private func performAppleGeocoding(coordinate: CLLocationCoordinate2D) async -> LocationInfo? {
        let geocoder = CLGeocoder()
        let location = CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude)
        
        do {
            let placemarks = try await geocoder.reverseGeocodeLocation(location)
            guard let placemark = placemarks.first else { return nil }
            
            return LocationInfo(
                coordinate: coordinate,
                country: placemark.country,
                state: placemark.administrativeArea,
                city: placemark.locality,
                address: placemark.thoroughfare
            )
        } catch {
            return nil
        }
    }
    
    /// 腾讯地理编码
    private func performTencentGeocoding(coordinate: CLLocationCoordinate2D) async -> LocationInfo? {
        guard let addressInfo = await TencentMapsService.shared.reverseGeocodeWithSignature(coordinate: coordinate) else {
            return nil
        }
        
        return LocationInfo(
            coordinate: coordinate,
            country: addressInfo.country,
            state: addressInfo.province,
            city: addressInfo.city,
            address: addressInfo.formattedAddress
        )
    }
    
    /// 高德地理编码
    private func performAMapGeocoding(coordinate: CLLocationCoordinate2D) async -> LocationInfo? {
        guard let addressInfo = await AMapService.shared.reverseGeocode(coordinate: coordinate) else {
            return nil
        }
        
        return LocationInfo(
            coordinate: coordinate,
            country: addressInfo.country,
            state: addressInfo.province,
            city: addressInfo.city,
            address: addressInfo.formattedAddress
        )
    }
    
    /// OpenStreet地理编码
    private func performOSMGeocoding(coordinate: CLLocationCoordinate2D) async -> LocationInfo? {
        guard let addressInfo = await OpenStreetMapService.shared.reverseGeocode(coordinate: coordinate) else {
            return nil
        }
        
        return LocationInfo(
            coordinate: coordinate,
            country: addressInfo.country,
            state: addressInfo.province,
            city: addressInfo.city,
            address: addressInfo.formattedAddress
        )
    }
}

// MARK: - 地点分组结构

struct LocationGroup: Identifiable {
    let id: String // 改为String类型，使用稳定的内容id
    let country: String
    let city: String
    let detailedLocation: String? // 新增：详细地址
    let photos: [PhotoData]
    let coverPhoto: UIImage?
    let totalPhotos: Int
    let isParentNode: Bool // 是否为父节点
    let parentCity: String? // 父城市（仅子节点有）
    
    // 使用内容生成稳定的id
    init(country: String, city: String, detailedLocation: String?, photos: [PhotoData], coverPhoto: UIImage?, totalPhotos: Int, isParentNode: Bool, parentCity: String?) {
        self.country = country
        self.city = city
        self.detailedLocation = detailedLocation
        self.photos = photos
        self.coverPhoto = coverPhoto
        self.totalPhotos = totalPhotos
        self.isParentNode = isParentNode
        self.parentCity = parentCity
        
        // 生成稳定的id：父节点用城市名，子节点用城市+详细地址
        if isParentNode {
            self.id = "\(country)_\(city)_parent"
        } else {
            let detailed = detailedLocation ?? "unknown"
            self.id = "\(country)_\(city)_\(detailed)_child"
        }
    }
    
    var displayName: String {
        if isParentNode {
            // 父节点显示城市名称
            return city
        } else {
            // 子节点显示详细地址
            if let detailedLocation = detailedLocation, !detailedLocation.isEmpty {
                return detailedLocation
            } else {
                return city
            }
        }
    }
    
    var fullDisplayName: String {
        if isParentNode {
            return "\(city), \(country)"
        } else {
            if let detailedLocation = detailedLocation, !detailedLocation.isEmpty {
                return "\(detailedLocation), \(city)"
            } else {
                return "\(city), \(country)"
            }
        }
    }
}

// MARK: - LocationInfo 扩展，判断是否未知
extension LocationInfo {
    var isUnknown: Bool {
        let unknownCities = ["未知城市", "未知", nil]
        let unknownCountries = ["未知国家", "未知", nil]
        let unknownAddresses = ["未知地点", "未知", nil]
        return unknownCities.contains(self.city) || unknownCountries.contains(self.country) || unknownAddresses.contains(self.address)
    }
} 